- Timestamp:
- Aug 31, 2023, 11:31:15 PM (2 years ago)
- Branches:
- master
- Children:
- 950c58e
- Parents:
- 92355883 (diff), 686912c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- src
- Files:
-
- 41 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Create.cpp
r92355883 r2a301ff 42 42 return nullptr; 43 43 } 44 return new ast::FunctionDecl( decl->location, 45 decl->name, 46 vectorCopy( decl->type_params ), 47 vectorCopy( decl->assertions ), 48 vectorCopy( decl->params ), 49 vectorCopy( decl->returns ), 50 nullptr, 51 decl->storage, 52 decl->linkage, 53 vectorCopy( decl->attributes ), 54 decl->funcSpec, 55 decl->type->isVarArgs 56 ); 44 // The cast and changing the original should be safe as long as the 45 // change is reverted before anything else sees it. It's also faster. 46 FunctionDecl * mutDecl = const_cast<FunctionDecl *>( decl ); 47 CompoundStmt const * stmts = mutDecl->stmts.release(); 48 FunctionDecl * copy = deepCopy( mutDecl ); 49 mutDecl->stmts = stmts; 50 return copy; 57 51 } 58 52 -
src/AST/Decl.cpp
r92355883 r2a301ff 115 115 static_assert( sizeof(kindNames) / sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." ); 116 116 assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." ); 117 return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0' 117 // sizeof("sized") includes '\0' and gives the offset to remove "sized ". 118 return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; 118 119 } 119 120 -
src/AST/Decl.hpp
r92355883 r2a301ff 69 69 public: 70 70 /// Represents the type with all types and typedefs expanded. 71 /// This field is generated by SymTab::Validate::Pass272 71 std::string mangleName; 73 72 /// Stores the scope level at which the variable was declared. -
src/AST/LinkageSpec.cpp
r92355883 r2a301ff 27 27 namespace Linkage { 28 28 29 Spec update( CodeLocation loc, Spec spec, const std::string * cmd ) { 30 assert( cmd ); 31 std::unique_ptr<const std::string> guard( cmd ); // allocated by lexer 32 if ( *cmd == "\"Cforall\"" ) { 33 spec.is_mangled = true; 34 return spec; 35 } else if ( *cmd == "\"C\"" ) { 36 spec.is_mangled = false; 37 return spec; 38 } else { 39 SemanticError( loc, "Invalid linkage specifier " + *cmd ); 40 } 29 Spec update( CodeLocation loc, Spec spec, const std::string * cmd ) { 30 assert( cmd ); 31 std::unique_ptr<const std::string> guard( cmd ); // allocated by lexer 32 if ( *cmd == "\"Cforall\"" ) { 33 spec.is_mangled = true; 34 return spec; 35 } else if ( *cmd == "\"C\"" ) { 36 spec.is_mangled = false; 37 return spec; 38 } else { 39 SemanticError( loc, "Invalid linkage specifier " + *cmd ); 41 40 } 41 } 42 42 43 44 std::string name( Spec spec ) { 45 switch ( spec.val ) { 46 case Intrinsic.val: return "intrinsic"; 47 case C.val: return "C"; 48 case Cforall.val: return "Cforall"; 49 case AutoGen.val: return "autogenerated cfa"; 50 case Compiler.val: return "compiler built-in"; 51 case BuiltinCFA.val: return "cfa built-in"; 52 case BuiltinC.val: return "c built-in"; 53 default: return "<unnamed linkage spec>"; 54 } 43 std::string name( Spec spec ) { 44 switch ( spec.val ) { 45 case Intrinsic.val: return "intrinsic"; 46 case C.val: return "C"; 47 case Cforall.val: return "Cforall"; 48 case AutoGen.val: return "autogenerated cfa"; 49 case Compiler.val: return "compiler built-in"; 50 case BuiltinCFA.val: return "cfa built-in"; 51 case BuiltinC.val: return "c built-in"; 52 default: return "<unnamed linkage spec>"; 55 53 } 54 } 56 55 57 56 } -
src/AST/LinkageSpec.hpp
r92355883 r2a301ff 25 25 namespace Linkage { 26 26 27 /// Bitflags for linkage specifiers 28 enum { 29 Mangle = 1 << 0, 30 Generate = 1 << 1, 31 Overrideable = 1 << 2, 32 Builtin = 1 << 3, 33 GccBuiltin = 1 << 4 27 /// Bitflags for linkage specifiers 28 enum { 29 Mangle = 1 << 0, 30 Generate = 1 << 1, 31 Overrideable = 1 << 2, 32 Builtin = 1 << 3, 33 GccBuiltin = 1 << 4 34 }; 35 36 /// Bitflag type for storage classes 37 struct spec_flags { 38 union { 39 unsigned int val; 40 struct { 41 bool is_mangled : 1; 42 bool is_generatable : 1; 43 bool is_overrideable : 1; 44 bool is_builtin : 1; 45 bool is_gcc_builtin : 1; 46 }; 34 47 }; 35 48 36 /// Bitflag type for storage classes 37 struct spec_flags { 38 union { 39 unsigned int val; 40 struct { 41 bool is_mangled : 1; 42 bool is_generatable : 1; 43 bool is_overrideable : 1; 44 bool is_builtin : 1; 45 bool is_gcc_builtin : 1; 46 }; 47 }; 49 constexpr spec_flags( unsigned int val ) : val(val) {} 50 }; 48 51 49 constexpr spec_flags( unsigned int val ) : val(val) {} 50 }; 52 using Spec = bitfield<spec_flags>; 51 53 52 using Spec = bitfield<spec_flags>; 54 /// If `cmd` = "C" returns `spec` with `is_mangled = false`. 55 /// If `cmd` = "Cforall" returns `spec` with `is_mangled = true`. 56 Spec update( CodeLocation loc, Spec spec, const std::string * cmd ); 53 57 54 /// If `cmd` = "C" returns `spec` with `is_mangled = false`. 55 /// If `cmd` = "Cforall" returns `spec` with `is_mangled = true`. 56 Spec update( CodeLocation loc, Spec spec, const std::string * cmd ); 58 /// A human-readable name for this spec 59 std::string name( Spec spec ); 57 60 58 /// A human-readable name for this spec 59 std::string name( Spec spec ); 61 // Pre-defined flag combinations 60 62 61 // Pre-defined flag combinations 63 /// C built-in defined in prelude 64 constexpr Spec Intrinsic = { Mangle | Generate | Overrideable | Builtin }; 65 /// Ordinary Cforall 66 constexpr Spec Cforall = { Mangle | Generate }; 67 /// C code: not overloadable, not mangled 68 constexpr Spec C = { Generate }; 69 /// Built by translator (e.g. struct assignment) 70 constexpr Spec AutoGen = { Mangle | Generate | Overrideable }; 71 /// GCC internal 72 constexpr Spec Compiler = { Mangle | Builtin | GccBuiltin }; 73 /// Mangled builtins 74 constexpr Spec BuiltinCFA = { Mangle | Generate | Builtin }; 75 /// Non-mangled builtins 76 constexpr Spec BuiltinC = { Generate | Builtin }; 62 77 63 /// C built-in defined in prelude64 constexpr Spec Intrinsic = { Mangle | Generate | Overrideable | Builtin };65 /// Ordinary Cforall66 constexpr Spec Cforall = { Mangle | Generate };67 /// C code: not overloadable, not mangled68 constexpr Spec C = { Generate };69 /// Built by translator (e.g. struct assignment)70 constexpr Spec AutoGen = { Mangle | Generate | Overrideable };71 /// GCC internal72 constexpr Spec Compiler = { Mangle | Builtin | GccBuiltin };73 /// Mangled builtins74 constexpr Spec BuiltinCFA = { Mangle | Generate | Builtin };75 /// Non-mangled builtins76 constexpr Spec BuiltinC = { Generate | Builtin };77 78 } 78 79 -
src/AST/Pass.impl.hpp
r92355883 r2a301ff 53 53 #endif 54 54 55 namespace ast { 55 namespace ast::__pass { 56 // Check if this is either a null pointer or a pointer to an empty container 57 template<typename T> 58 static inline bool empty( T * ptr ) { 59 return !ptr || ptr->empty(); 60 } 61 62 template< typename core_t, typename node_t > 63 static inline node_t* mutate(const node_t *node) { 64 return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node); 65 } 66 67 //------------------------------ 68 template<typename it_t, template <class...> class container_t> 69 static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) { 70 if ( empty( decls ) ) return; 71 72 std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto { 73 return new DeclStmt( decl->location, decl ); 74 }); 75 decls->clear(); 76 if ( mutated ) *mutated = true; 77 } 78 79 template<typename it_t, template <class...> class container_t> 80 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) { 81 if ( empty( stmts ) ) return; 82 83 std::move(stmts->begin(), stmts->end(), it); 84 stmts->clear(); 85 if ( mutated ) *mutated = true; 86 } 87 88 //------------------------------ 89 /// Check if should be skipped, different for pointers and containers 56 90 template<typename node_t> 57 node_t * shallowCopy( const node_t * node ); 58 59 namespace __pass { 60 // Check if this is either a null pointer or a pointer to an empty container 61 template<typename T> 62 static inline bool empty( T * ptr ) { 63 return !ptr || ptr->empty(); 64 } 65 66 template< typename core_t, typename node_t > 67 static inline node_t* mutate(const node_t *node) { 68 return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node); 69 } 70 71 //------------------------------ 72 template<typename it_t, template <class...> class container_t> 73 static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) { 74 if ( empty( decls ) ) return; 75 76 std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto { 77 return new DeclStmt( decl->location, decl ); 78 }); 79 decls->clear(); 80 if ( mutated ) *mutated = true; 81 } 82 83 template<typename it_t, template <class...> class container_t> 84 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) { 85 if ( empty( stmts ) ) return; 86 87 std::move(stmts->begin(), stmts->end(), it); 88 stmts->clear(); 89 if ( mutated ) *mutated = true; 90 } 91 92 //------------------------------ 93 /// Check if should be skipped, different for pointers and containers 94 template<typename node_t> 95 bool skip( const ast::ptr<node_t> & val ) { 96 return !val; 97 } 98 99 template< template <class...> class container_t, typename node_t > 100 bool skip( const container_t<ast::ptr< node_t >> & val ) { 101 return val.empty(); 102 } 103 104 //------------------------------ 105 /// Get the value to visit, different for pointers and containers 106 template<typename node_t> 107 auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) { 108 return val.get(); 109 } 110 111 template<typename node_t> 112 const node_t & get( const node_t & val, long ) { 113 return val; 114 } 115 116 //------------------------------ 117 /// Check if value was mutated, different for pointers and containers 118 template<typename lhs_t, typename rhs_t> 119 bool differs( const lhs_t * old_val, const rhs_t * new_val ) { 120 return old_val != new_val; 121 } 122 123 template< template <class...> class container_t, typename node_t > 124 bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) { 125 return !new_val.empty(); 126 } 91 bool skip( const ast::ptr<node_t> & val ) { 92 return !val; 93 } 94 95 template< template <class...> class container_t, typename node_t > 96 bool skip( const container_t<ast::ptr< node_t >> & val ) { 97 return val.empty(); 98 } 99 100 //------------------------------ 101 /// Get the value to visit, different for pointers and containers 102 template<typename node_t> 103 auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) { 104 return val.get(); 105 } 106 107 template<typename node_t> 108 const node_t & get( const node_t & val, long ) { 109 return val; 110 } 111 112 //------------------------------ 113 /// Check if value was mutated, different for pointers and containers 114 template<typename lhs_t, typename rhs_t> 115 bool differs( const lhs_t * old_val, const rhs_t * new_val ) { 116 return old_val != new_val; 117 } 118 119 template< template <class...> class container_t, typename node_t > 120 bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) { 121 return !new_val.empty(); 127 122 } 128 123 } … … 1920 1915 VISIT_START( node ); 1921 1916 1922 __pass::symtab::addStruct ( core, 0, node->name );1917 __pass::symtab::addStructId( core, 0, node->name ); 1923 1918 1924 1919 if ( __visit_children() ) { … … 1936 1931 VISIT_START( node ); 1937 1932 1938 __pass::symtab::addUnion ( core, 0, node->name );1933 __pass::symtab::addUnionId( core, 0, node->name ); 1939 1934 1940 1935 if ( __visit_children() ) { -
src/AST/Pass.proto.hpp
r92355883 r2a301ff 488 488 489 489 template<typename core_t> 490 static inline auto addStruct ( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {490 static inline auto addStructId( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStructId( str ), void() ) { 491 491 if ( ! core.symtab.lookupStruct( str ) ) { 492 core.symtab.addStruct ( str );493 } 494 } 495 496 template<typename core_t> 497 static inline void addStruct ( core_t &, long, const std::string & ) {}498 499 template<typename core_t> 500 static inline auto addUnion ( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {492 core.symtab.addStructId( str ); 493 } 494 } 495 496 template<typename core_t> 497 static inline void addStructId( core_t &, long, const std::string & ) {} 498 499 template<typename core_t> 500 static inline auto addUnionId( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnionId( str ), void() ) { 501 501 if ( ! core.symtab.lookupUnion( str ) ) { 502 core.symtab.addUnion ( str );503 } 504 } 505 506 template<typename core_t> 507 static inline void addUnion ( core_t &, long, const std::string & ) {}502 core.symtab.addUnionId( str ); 503 } 504 } 505 506 template<typename core_t> 507 static inline void addUnionId( core_t &, long, const std::string & ) {} 508 508 509 509 #undef SYMTAB_FUNC1 -
src/AST/SymbolTable.cpp
r92355883 r2a301ff 19 19 20 20 #include "Copy.hpp" 21 #include <iostream>22 #include <algorithm>23 24 21 #include "Decl.hpp" 25 22 #include "Expr.hpp" … … 206 203 out.push_back(decl.second); 207 204 } 208 209 // std::cerr << otypeKey << ' ' << out.size() << std::endl;210 205 } 211 206 … … 328 323 } 329 324 330 void SymbolTable::addStruct ( const std::string &id ) {325 void SymbolTable::addStructId( const std::string &id ) { 331 326 addStruct( new StructDecl( CodeLocation(), id ) ); 332 327 } … … 370 365 } 371 366 372 void SymbolTable::addUnion ( const std::string &id ) {367 void SymbolTable::addUnionId( const std::string &id ) { 373 368 addUnion( new UnionDecl( CodeLocation(), id ) ); 374 369 } -
src/AST/SymbolTable.hpp
r92355883 r2a301ff 150 150 void addType( const NamedTypeDecl * decl ); 151 151 /// Adds a struct declaration to the symbol table by name 152 void addStruct ( const std::string & id );152 void addStructId( const std::string & id ); 153 153 /// Adds a struct declaration to the symbol table 154 154 void addStruct( const StructDecl * decl ); … … 156 156 void addEnum( const EnumDecl * decl ); 157 157 /// Adds a union declaration to the symbol table by name 158 void addUnion ( const std::string & id );158 void addUnionId( const std::string & id ); 159 159 /// Adds a union declaration to the symbol table 160 160 void addUnion( const UnionDecl * decl ); -
src/AST/Util.cpp
r92355883 r2a301ff 20 20 #include "Pass.hpp" 21 21 #include "TranslationUnit.hpp" 22 #include "Common/utility.h" 23 #include "GenPoly/ScopedSet.h" 22 24 23 25 #include <vector> 26 27 using GenPoly::ScopedSet; 24 28 25 29 namespace ast { … … 102 106 } 103 107 108 /// Check for Floating Nodes: 109 /// Every node should be reachable from a root (the TranslationUnit) via a 110 /// chain of structural references (tracked with ptr). This cannot check all 111 /// of that, it just checks if a given node's field has a strong reference. 112 template<typename node_t, typename field_t> 113 void noFloatingNode( const node_t * node, field_t node_t::*field_ptr ) { 114 const field_t & field = node->*field_ptr; 115 if ( nullptr == field ) return; 116 assertf( field->isManaged(), "Floating node found." ); 117 } 118 104 119 struct InvariantCore { 105 120 // To save on the number of visits: this is a kind of composed core. … … 127 142 } 128 143 144 void previsit( const VariableExpr * node ) { 145 previsit( (const ParseNode *)node ); 146 noFloatingNode( node, &VariableExpr::var ); 147 } 148 129 149 void previsit( const MemberExpr * node ) { 130 150 previsit( (const ParseNode *)node ); … … 132 152 } 133 153 154 void previsit( const StructInstType * node ) { 155 previsit( (const Node *)node ); 156 noFloatingNode( node, &StructInstType::base ); 157 } 158 159 void previsit( const UnionInstType * node ) { 160 previsit( (const Node *)node ); 161 noFloatingNode( node, &UnionInstType::base ); 162 } 163 164 void previsit( const EnumInstType * node ) { 165 previsit( (const Node *)node ); 166 noFloatingNode( node, &EnumInstType::base ); 167 } 168 169 void previsit( const TypeInstType * node ) { 170 previsit( (const Node *)node ); 171 noFloatingNode( node, &TypeInstType::base ); 172 } 173 134 174 void postvisit( const Node * node ) { 135 175 no_strong_cycles.postvisit( node ); … … 137 177 }; 138 178 179 /// Checks that referred to nodes are in scope. 180 /// This checks many readonly pointers to see if the declaration they are 181 /// referring to is in scope by the structural rules of code. 182 // Any escapes marked with a bug should be removed once the bug is fixed. 183 struct InScopeCore : public ast::WithShortCircuiting { 184 ScopedSet<DeclWithType const *> typedDecls; 185 ScopedSet<TypeDecl const *> typeDecls; 186 // These 3 are really hard to check, because uses that originally ref. at 187 // a forward declaration can be rewired to point a later full definition. 188 ScopedSet<StructDecl const *> structDecls; 189 ScopedSet<UnionDecl const *> unionDecls; 190 ScopedSet<EnumDecl const *> enumDecls; 191 ScopedSet<TraitDecl const *> traitDecls; 192 193 bool isInGlobal = false; 194 195 void beginScope() { 196 typedDecls.beginScope(); 197 typeDecls.beginScope(); 198 structDecls.beginScope(); 199 unionDecls.beginScope(); 200 enumDecls.beginScope(); 201 traitDecls.beginScope(); 202 } 203 204 void endScope() { 205 typedDecls.endScope(); 206 typeDecls.endScope(); 207 structDecls.endScope(); 208 unionDecls.endScope(); 209 enumDecls.endScope(); 210 traitDecls.endScope(); 211 } 212 213 void previsit( ApplicationExpr const * expr ) { 214 // All isInGlobal manipulation is just to isolate this check. 215 // The invalid compound literals lead to bad ctor/dtors. [#280] 216 VariableExpr const * func = nullptr; 217 CastExpr const * cast = nullptr; 218 VariableExpr const * arg = nullptr; 219 if ( isInGlobal 220 && 1 == expr->args.size() 221 && ( func = expr->func.as<VariableExpr>() ) 222 && ( "?{}" == func->var->name || "^?{}" == func->var->name ) 223 && ( cast = expr->args[0].as<CastExpr>() ) 224 && ( arg = cast->arg.as<VariableExpr>() ) 225 && isPrefix( arg->var->name, "_compLit" ) ) { 226 visit_children = false; 227 } 228 } 229 230 void previsit( VariableExpr const * expr ) { 231 if ( !expr->var ) return; 232 // bitwise assignment escape [#281] 233 if ( expr->var->location.isUnset() ) return; 234 assert( typedDecls.contains( expr->var ) ); 235 } 236 237 void previsit( FunctionType const * type ) { 238 // This is to avoid checking the assertions, which can point at the 239 // function's declaration and not the enclosing function. 240 for ( auto type_param : type->forall ) { 241 if ( type_param->formal_usage ) { 242 visit_children = false; 243 // We could check non-assertion fields here. 244 } 245 } 246 } 247 248 void previsit( TypeInstType const * type ) { 249 if ( !type->base ) return; 250 assertf( type->base->isManaged(), "Floating Node" ); 251 252 // bitwise assignment escape [#281] 253 if ( type->base->location.isUnset() ) return; 254 // Formal types can actually look at out of scope variables. 255 if ( type->formal_usage ) return; 256 assert( typeDecls.contains( type->base ) ); 257 } 258 259 void previsit( TraitInstType const * type ) { 260 if ( !type->base ) return; 261 assert( traitDecls.contains( type->base ) ); 262 } 263 264 void previsit( ObjectDecl const * decl ) { 265 typedDecls.insert( decl ); 266 // There are some ill-formed compound literals. [#280] 267 // The only known problem cases are at the top level. 268 if ( isPrefix( decl->name, "_compLit" ) ) { 269 visit_children = false; 270 } 271 } 272 273 void previsit( FunctionDecl const * decl ) { 274 typedDecls.insert( decl ); 275 beginScope(); 276 for ( auto & type_param : decl->type_params ) { 277 typeDecls.insert( type_param ); 278 } 279 for ( auto & assertion : decl->assertions ) { 280 typedDecls.insert( assertion ); 281 } 282 for ( auto & param : decl->params ) { 283 typedDecls.insert( param ); 284 } 285 for ( auto & ret : decl->returns ) { 286 typedDecls.insert( ret ); 287 } 288 // No special handling of withExprs. 289 290 // Part of the compound literal escape. [#280] 291 if ( "__global_init__" == decl->name 292 || "__global_destroy__" == decl->name ) { 293 assert( !isInGlobal ); 294 isInGlobal = true; 295 } 296 } 297 298 void postvisit( FunctionDecl const * decl ) { 299 endScope(); 300 // Part of the compound literal escape. [#280] 301 if ( isInGlobal && ( "__global_init__" == decl->name 302 || "__global_destroy__" == decl->name ) ) { 303 isInGlobal = false; 304 } 305 } 306 307 void previsit( StructDecl const * decl ) { 308 structDecls.insert( decl ); 309 beginScope(); 310 for ( auto & type_param : decl->params ) { 311 typeDecls.insert( type_param ); 312 } 313 } 314 315 void postvisit( StructDecl const * ) { 316 endScope(); 317 } 318 319 void previsit( UnionDecl const * decl ) { 320 unionDecls.insert( decl ); 321 beginScope(); 322 for ( auto & type_param : decl->params ) { 323 typeDecls.insert( type_param ); 324 } 325 } 326 327 void postvisit( UnionDecl const * ) { 328 endScope(); 329 } 330 331 void previsit( EnumDecl const * decl ) { 332 enumDecls.insert( decl ); 333 if ( ast::EnumDecl::EnumHiding::Visible == decl->hide ) { 334 for ( auto & member : decl->members ) { 335 typedDecls.insert( member.strict_as<ast::DeclWithType>() ); 336 } 337 } 338 beginScope(); 339 for ( auto & type_param : decl->params ) { 340 typeDecls.insert( type_param ); 341 } 342 } 343 344 void postvisit( EnumDecl const * ) { 345 endScope(); 346 } 347 348 void previsit( TraitDecl const * decl ) { 349 traitDecls.insert( decl ); 350 beginScope(); 351 for ( auto & type_param : decl->params ) { 352 typeDecls.insert( type_param ); 353 } 354 } 355 356 void postvisit( TraitDecl const * ) { 357 endScope(); 358 } 359 360 void previsit( Designation const * ) { 361 visit_children = false; 362 } 363 }; 364 139 365 } // namespace 140 366 141 367 void checkInvariants( TranslationUnit & transUnit ) { 142 ast::Pass<InvariantCore>::run( transUnit ); 368 Pass<InvariantCore>::run( transUnit ); 369 Pass<InScopeCore>::run( transUnit ); 143 370 } 144 371 -
src/Common/ScopedMap.h
r92355883 r2a301ff 199 199 friend class ScopedMap; 200 200 friend class const_iterator; 201 typedef typename ScopedMap::MapType::iterator wrapped_iterator; 202 typedef typename ScopedMap::ScopeList scope_list; 203 typedef typename scope_list::size_type size_type; 201 typedef typename MapType::iterator wrapped_iterator; 202 typedef typename ScopeList::size_type size_type; 204 203 205 204 /// Checks if this iterator points to a valid item … … 220 219 } 221 220 222 iterator( scope_list & _scopes, const wrapped_iterator & _it, size_type inLevel)221 iterator(ScopeList & _scopes, const wrapped_iterator & _it, size_type inLevel) 223 222 : scopes(&_scopes), it(_it), level(inLevel) {} 224 223 public: … … 266 265 267 266 private: 268 scope_list *scopes;267 ScopeList *scopes; 269 268 wrapped_iterator it; 270 269 size_type level; -
src/Concurrency/KeywordsNew.cpp
r92355883 r2a301ff 534 534 void ConcurrentSueKeyword::addGetRoutines( 535 535 const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) { 536 // Clone the signature and then build the body. 537 ast::FunctionDecl * decl = ast::deepCopy( forward ); 538 536 539 // Say it is generated at the "same" places as the forward declaration. 537 const CodeLocation & location = forward->location;538 539 const ast::DeclWithType * param = forward->params.front();540 const CodeLocation & location = decl->location; 541 542 const ast::DeclWithType * param = decl->params.front(); 540 543 ast::Stmt * stmt = new ast::ReturnStmt( location, 541 544 new ast::AddressExpr( location, … … 551 554 ); 552 555 553 ast::FunctionDecl * decl = ast::deepCopy( forward );554 556 decl->stmts = new ast::CompoundStmt( location, { stmt } ); 555 557 declsToAddAfter.push_back( decl ); … … 1236 1238 } 1237 1239 1240 void flattenTuple( const ast::UntypedTupleExpr * tuple, std::vector<ast::ptr<ast::Expr>> & output ) { 1241 for ( auto & expr : tuple->exprs ) { 1242 const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get()); 1243 if ( innerTuple ) flattenTuple( innerTuple, output ); 1244 else output.emplace_back( ast::deepCopy( expr )); 1245 } 1246 } 1247 1238 1248 ast::CompoundStmt * MutexKeyword::addStatements( 1239 1249 const ast::CompoundStmt * body, … … 1248 1258 // std::string lockFnName = mutex_func_namer.newName(); 1249 1259 // std::string unlockFnName = mutex_func_namer.newName(); 1260 1261 // If any arguments to the mutex stmt are tuples, flatten them 1262 std::vector<ast::ptr<ast::Expr>> flattenedArgs; 1263 for ( auto & arg : args ) { 1264 const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get()); 1265 if ( tuple ) flattenTuple( tuple, flattenedArgs ); 1266 else flattenedArgs.emplace_back( ast::deepCopy( arg )); 1267 } 1250 1268 1251 1269 // Make pointer to the monitors. … … 1257 1275 new ast::VoidType() 1258 1276 ), 1259 ast::ConstantExpr::from_ulong( location, args.size() ),1277 ast::ConstantExpr::from_ulong( location, flattenedArgs.size() ), 1260 1278 ast::FixedLen, 1261 1279 ast::DynamicDim … … 1264 1282 location, 1265 1283 map_range<std::vector<ast::ptr<ast::Init>>>( 1266 args, [](const ast::Expr * expr) {1284 flattenedArgs, [](const ast::Expr * expr) { 1267 1285 return new ast::SingleInit( 1268 1286 expr->location, … … 1287 1305 1288 1306 // adds a nested try stmt for each lock we are locking 1289 for ( long unsigned int i = 0; i < args.size(); i++ ) {1307 for ( long unsigned int i = 0; i < flattenedArgs.size(); i++ ) { 1290 1308 ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 1291 1309 location, … … 1298 1316 // make the try body 1299 1317 ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location ); 1300 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess );1318 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", flattenedArgs, location, innerAccess ); 1301 1319 currTryBody->push_back( lockCall ); 1302 1320 1303 1321 // make the finally stmt 1304 1322 ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location ); 1305 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess );1323 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", flattenedArgs, location, innerAccess ); 1306 1324 currFinallyBody->push_back( unlockCall ); 1307 1325 … … 1343 1361 new ast::SingleInit( 1344 1362 location, 1345 ast::ConstantExpr::from_ulong( location, args.size() ) ),1363 ast::ConstantExpr::from_ulong( location, flattenedArgs.size() ) ), 1346 1364 }, 1347 1365 {}, -
src/Concurrency/Waituntil.cpp
r92355883 r2a301ff 142 142 UniqueName namer_target = "__clause_target_"s; 143 143 UniqueName namer_when = "__when_cond_"s; 144 UniqueName namer_label = "__waituntil_label_"s; 144 145 145 146 string idxName = "__CFA_clause_idx_"; … … 173 174 void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName ); 174 175 void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ); 175 ForStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );176 CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ); 176 177 Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName ); 177 178 CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data ); 178 179 Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData ); 179 Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & satName, string &runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );180 Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ); 180 181 void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName ); 181 182 Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName ); … … 626 627 return new CompoundStmt( cLoc, 627 628 { 628 new ExprStmt( cLoc,629 genSelectTraitCall( clause, data, "on_selected" ) 630 ),631 ast::deepCopy( clause->stmt)629 new IfStmt( cLoc, 630 genSelectTraitCall( clause, data, "on_selected" ), 631 ast::deepCopy( clause->stmt ) 632 ) 632 633 } 633 634 ); … … 653 654 } 654 655 }*/ 655 ForStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {656 CompoundStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) { 656 657 CompoundStmt * ifBody = new CompoundStmt( stmt->location ); 657 658 const CodeLocation & loc = stmt->location; 659 660 string switchLabel = namer_label.newName(); 658 661 659 662 /* generates: … … 707 710 ) 708 711 ), 709 new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc ) )712 new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) ) 710 713 } 711 714 ) … … 719 722 new SwitchStmt( loc, 720 723 new NameExpr( loc, idxName ), 721 std::move( switchCases ) 724 std::move( switchCases ), 725 { Label( loc, switchLabel ) } 722 726 ) 723 727 ); … … 744 748 ); 745 749 746 return new ForStmt( loc, 750 string forLabel = namer_label.newName(); 751 752 // we hoist init here so that this pass can happen after hoistdecls pass 753 return new CompoundStmt( loc, 747 754 { 748 755 new DeclStmt( loc, … … 752 759 new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) ) 753 760 ) 754 ) 755 }, // inits 756 new UntypedExpr ( loc, 757 new NameExpr( loc, "?<?" ), 758 { 759 new NameExpr( loc, idxName ), 760 ConstantExpr::from_int( loc, stmt->clauses.size() ) 761 } 762 ), // cond 763 new UntypedExpr ( loc, 764 new NameExpr( loc, "?++" ), 765 { new NameExpr( loc, idxName ) } 766 ), // inc 767 new CompoundStmt( loc, 768 { 769 new IfStmt( loc, 770 new UntypedExpr ( loc, 771 new NameExpr( loc, predName ), 772 { new NameExpr( loc, clauseData.at(0)->statusName ) } 773 ), 774 new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc ) ) 775 ), 776 ifSwitch 777 } 778 ) // body 761 ), 762 new ForStmt( loc, 763 {}, // inits 764 new UntypedExpr ( loc, 765 new NameExpr( loc, "?<?" ), 766 { 767 new NameExpr( loc, idxName ), 768 ConstantExpr::from_int( loc, stmt->clauses.size() ) 769 } 770 ), // cond 771 new UntypedExpr ( loc, 772 new NameExpr( loc, "?++" ), 773 { new NameExpr( loc, idxName ) } 774 ), // inc 775 new CompoundStmt( loc, 776 { 777 new IfStmt( loc, 778 new UntypedExpr ( loc, 779 new NameExpr( loc, predName ), 780 { new NameExpr( loc, clauseData.at(0)->statusName ) } 781 ), 782 new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) ) 783 ), 784 ifSwitch 785 } 786 ), // body 787 { Label( loc, forLabel ) } 788 ) 789 } 779 790 ); 780 791 } … … 809 820 } 810 821 811 Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & satName, string &runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {822 Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) { 812 823 CompoundStmt * whileBody = new CompoundStmt( stmt->location ); 813 824 const CodeLocation & loc = stmt->location; … … 823 834 ); 824 835 825 whileBody->push_back( genStatusCheckFor( stmt, clauseData, satName ) );836 whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) ); 826 837 827 838 return new CompoundStmt( loc, 828 839 { 829 840 new WhileDoStmt( loc, 830 genNotSatExpr( stmt, satName, arrName ),841 genNotSatExpr( stmt, runName, arrName ), 831 842 whileBody, // body 832 843 {} // no inits 833 ), 834 genStatusCheckFor( stmt, clauseData, runName ) 844 ) 835 845 } 836 846 ); … … 856 866 new ObjectDecl( cLoc, 857 867 currClause->targetName, 858 new ReferenceType( new TypeofType( ast::deepCopy( stmt->clauses.at(i)->target ) ) ), 868 new ReferenceType( 869 new TypeofType( new UntypedExpr( cLoc, 870 new NameExpr( cLoc, "__CFA_select_get_type" ), 871 { ast::deepCopy( stmt->clauses.at(i)->target ) } 872 )) 873 ), 859 874 new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) ) 860 875 ) … … 1268 1283 new NameExpr( stmt->else_cond->location, elseWhenName ), 1269 1284 genElseClauseBranch( stmt, runName, statusArrName, clauseData ), 1270 genNoElseClauseBranch( stmt, satName,runName, statusArrName, pCountName, clauseData )1285 genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) 1271 1286 ) 1272 1287 ); 1273 1288 } else if ( !stmt->else_stmt ) { // normal gen 1274 tryBody->push_back( genNoElseClauseBranch( stmt, satName,runName, statusArrName, pCountName, clauseData ) );1289 tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) ); 1275 1290 } else { // generate just else 1276 1291 tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) ); 1277 1292 } 1278 1293 1294 // Collection of unregister calls on resources to be put in finally clause 1295 // for each clause: 1296 // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... } 1297 // OR if when( ... ) defined on resource 1298 // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... } 1279 1299 CompoundStmt * unregisters = new CompoundStmt( loc ); 1280 // generates for each clause: 1281 // if ( !has_run( clause_statuses[i] ) ) 1282 // OR if when_cond defined 1283 // if ( when_cond_i && !has_run( clause_statuses[i] ) ) 1284 // body of if is: 1285 // { if (unregister_select(A, clause1) && on_selected(A, clause1)) clause1->stmt; } // this conditionally runs the block unregister_select returns true (needed by some primitives) 1286 Expr * ifCond; 1287 UntypedExpr * statusExpr; // !clause_statuses[i] 1300 1301 Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] ) 1288 1302 for ( int i = 0; i < numClauses; i++ ) { 1289 1303 const CodeLocation & cLoc = stmt->clauses.at(i)->location; 1290 1304 1305 // Generates: !__CFA_has_clause_run( clause_statuses[i] ) 1291 1306 statusExpr = new UntypedExpr ( cLoc, 1292 1307 new NameExpr( cLoc, "!?" ), … … 1300 1315 } 1301 1316 ); 1302 1303 if ( stmt->clauses.at(i)->when_cond ) { 1304 // generates: if( when_cond_i && !has_run(clause_statuses[i]) ) 1305 ifCond = new LogicalExpr( cLoc, 1317 1318 // Generates: 1319 // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ); 1320 statusExpr = new LogicalExpr( cLoc, 1321 new CastExpr( cLoc, 1322 statusExpr, 1323 new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 1324 ), 1325 new CastExpr( cLoc, 1326 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ), 1327 new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 1328 ), 1329 LogicalFlag::AndExpr 1330 ); 1331 1332 // if when cond defined generates: 1333 // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ); 1334 if ( stmt->clauses.at(i)->when_cond ) 1335 statusExpr = new LogicalExpr( cLoc, 1306 1336 new CastExpr( cLoc, 1307 1337 new NameExpr( cLoc, clauseData.at(i)->whenName ), … … 1314 1344 LogicalFlag::AndExpr 1315 1345 ); 1316 } else // generates: if( !clause_statuses[i] ) 1317 ifCond = statusExpr;1318 1346 1347 // generates: 1348 // if ( statusExpr ) { ... clausei stmt ... } 1319 1349 unregisters->push_back( 1320 1350 new IfStmt( cLoc, 1321 ifCond,1351 statusExpr, 1322 1352 new CompoundStmt( cLoc, 1323 1353 { 1324 1354 new IfStmt( cLoc, 1325 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ), 1326 // ast::deepCopy( stmt->clauses.at(i)->stmt ) 1327 genStmtBlock( stmt->clauses.at(i), clauseData.at(i) ) 1355 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ), 1356 ast::deepCopy( stmt->clauses.at(i)->stmt ) 1328 1357 ) 1329 1358 } 1330 1359 ) 1331 1332 ) 1333 ); 1360 ) 1361 ); 1362 1363 // // generates: 1364 // // if ( statusExpr ) { ... clausei stmt ... } 1365 // unregisters->push_back( 1366 // new IfStmt( cLoc, 1367 // statusExpr, 1368 // genStmtBlock( stmt->clauses.at(i), clauseData.at(i) ) 1369 // ) 1370 // ); 1334 1371 } 1335 1372 -
src/ControlStruct/ExceptDeclNew.cpp
r92355883 r2a301ff 242 242 } 243 243 244 ast::ObjectDecl const* createExternVTable(244 ast::ObjectDecl * createExternVTable( 245 245 CodeLocation const & location, 246 246 std::string const & exceptionName, … … 299 299 } ), 300 300 ast::Storage::Classes(), 301 ast::Linkage::Cforall 301 ast::Linkage::Cforall, 302 { new ast::Attribute( "cfa_linkonce" ) } 302 303 ); 303 304 } … … 352 353 } ), 353 354 ast::Storage::Classes(), 354 ast::Linkage::Cforall 355 ); 356 } 357 358 ast::ObjectDecl const * createVirtualTable( 355 ast::Linkage::Cforall, 356 { new ast::Attribute( "cfa_linkonce" ) } 357 ); 358 } 359 360 ast::ObjectDecl * createVirtualTable( 359 361 CodeLocation const & location, 360 362 std::string const & exceptionName, … … 451 453 std::string const & tableName = decl->name; 452 454 455 ast::ObjectDecl * retDecl; 453 456 if ( decl->storage.is_extern ) { 454 457 // Unique type-ids are only needed for polymorphic instances. … … 457 460 createExternTypeId( location, exceptionName, params ) ); 458 461 } 459 ret urncreateExternVTable( location, exceptionName, params, tableName );462 retDecl = createExternVTable( location, exceptionName, params, tableName ); 460 463 } else { 461 464 // Unique type-ids are only needed for polymorphic instances. … … 468 471 declsToAddBefore.push_back( 469 472 createMsg( location, exceptionName, params ) ); 470 ret urncreateVirtualTable(473 retDecl = createVirtualTable( 471 474 location, exceptionName, params, tableName ); 472 475 } 476 477 for ( ast::ptr<ast::Attribute> const & attr : decl->attributes ) { 478 retDecl->attributes.push_back( attr ); 479 } 480 481 return retDecl; 473 482 } 474 483 … … 478 487 479 488 std::string vtableName = Virtual::vtableTypeName( inst->name ); 489 480 490 auto newType = new ast::StructInstType( vtableName ); 481 491 for ( ast::ptr<ast::Expr> const & param : inst->params ) { -
src/GenPoly/Box.cc
r92355883 r2a301ff 1538 1538 } 1539 1539 1540 /// Checks if memberDecl matches the decl from an aggregate. 1541 bool isMember( DeclarationWithType *memberDecl, Declaration * decl ) { 1542 if ( memberDecl->get_name() != decl->get_name() ) 1543 return false; 1544 1545 if ( memberDecl->get_name().empty() ) { 1546 // Plan-9 Field: match on unique_id. 1547 return ( memberDecl->get_uniqueId() == decl->get_uniqueId() ); 1548 } 1549 1550 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl ); 1551 1552 if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) { 1553 // Tuple-Element Field: expect neither had mangled name; accept match on simple name (like field_2) only. 1554 assert( memberDecl->get_mangleName().empty() && declWithType->get_mangleName().empty() ); 1555 return true; 1556 } 1557 1558 // Ordinary Field: Use full name to accommodate overloading. 1559 return ( memberDecl->get_mangleName() == declWithType->get_mangleName() ); 1560 } 1561 1540 1562 /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present 1541 1563 long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) { 1542 1564 for ( auto pair : enumerate( baseDecls ) ) { 1543 Declaration * decl = pair.val; 1544 size_t i = pair.idx; 1545 if ( memberDecl->get_name() != decl->get_name() ) 1546 continue; 1547 1548 if ( memberDecl->get_name().empty() ) { 1549 // plan-9 field: match on unique_id 1550 if ( memberDecl->get_uniqueId() == decl->get_uniqueId() ) 1551 return i; 1552 else 1553 continue; 1554 } 1555 1556 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl ); 1557 1558 if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) { 1559 // tuple-element field: expect neither had mangled name; accept match on simple name (like field_2) only 1560 assert( memberDecl->get_mangleName().empty() && declWithType->get_mangleName().empty() ); 1561 return i; 1562 } 1563 1564 // ordinary field: use full name to accommodate overloading 1565 if ( memberDecl->get_mangleName() == declWithType->get_mangleName() ) 1566 return i; 1567 else 1568 continue; 1565 if ( isMember( memberDecl, pair.val ) ) { 1566 return pair.idx; 1567 } 1569 1568 } 1570 1569 return -1; -
src/GenPoly/ErasableScopedMap.h
r92355883 r2a301ff 57 57 /// Starts a new scope 58 58 void beginScope() { 59 Scope scope; 60 scopes.push_back(scope); 59 scopes.emplace_back(); 61 60 } 62 61 … … 145 144 public std::iterator< std::bidirectional_iterator_tag, value_type > { 146 145 friend class ErasableScopedMap; 147 typedef typename std::map< Key, Value >::iterator wrapped_iterator; 148 typedef typename std::vector< std::map< Key, Value > > scope_list; 149 typedef typename scope_list::size_type size_type; 146 typedef typename Scope::iterator wrapped_iterator; 147 typedef typename ScopeList::size_type size_type; 150 148 151 149 /// Checks if this iterator points to a valid item -
src/GenPoly/ScopedSet.h
r92355883 r2a301ff 47 47 /// Starts a new scope 48 48 void beginScope() { 49 Scope scope; 50 scopes.push_back(scope); 49 scopes.emplace_back(); 51 50 } 52 51 … … 85 84 iterator findNext( const_iterator &it, const Value &key ) { 86 85 if ( it.i == 0 ) return end(); 87 86 for ( size_type i = it.i - 1; ; --i ) { 88 87 typename Scope::iterator val = scopes[i].find( key ); 89 88 if ( val != scopes[i].end() ) return iterator( scopes, val, i ); … … 112 111 friend class ScopedSet; 113 112 friend class const_iterator; 114 typedef typename std::set< Value >::iterator wrapped_iterator; 115 typedef typename std::vector< std::set< Value > > scope_list; 116 typedef typename scope_list::size_type size_type; 113 typedef typename Scope::iterator wrapped_iterator; 114 typedef typename ScopeList::size_type size_type; 117 115 118 116 /// Checks if this iterator points to a valid item … … 133 131 } 134 132 135 iterator( scope_list const &_scopes, const wrapped_iterator &_it, size_type _i)133 iterator(ScopeList const &_scopes, const wrapped_iterator &_it, size_type _i) 136 134 : scopes(&_scopes), it(_it), i(_i) {} 137 135 public: … … 176 174 177 175 private: 178 scope_list const *scopes;176 ScopeList const *scopes; 179 177 wrapped_iterator it; 180 178 size_type i; … … 185 183 public std::iterator< std::bidirectional_iterator_tag, value_type > { 186 184 friend class ScopedSet; 187 typedef typename std::set< Value >::iterator wrapped_iterator; 188 typedef typename std::set< Value >::const_iterator wrapped_const_iterator; 189 typedef typename std::vector< std::set< Value > > scope_list; 190 typedef typename scope_list::size_type size_type; 185 typedef typename Scope::iterator wrapped_iterator; 186 typedef typename Scope::const_iterator wrapped_const_iterator; 187 typedef typename ScopeList::size_type size_type; 191 188 192 189 /// Checks if this iterator points to a valid item … … 207 204 } 208 205 209 const_iterator( scope_list const &_scopes, const wrapped_const_iterator &_it, size_type _i)206 const_iterator(ScopeList const &_scopes, const wrapped_const_iterator &_it, size_type _i) 210 207 : scopes(&_scopes), it(_it), i(_i) {} 211 208 public: … … 255 252 256 253 private: 257 scope_list const *scopes;254 ScopeList const *scopes; 258 255 wrapped_const_iterator it; 259 256 size_type i; -
src/GenPoly/SpecializeNew.cpp
r92355883 r2a301ff 104 104 105 105 bool needsPolySpecialization( 106 const ast::Type * formalType,106 const ast::Type * /*formalType*/, 107 107 const ast::Type * actualType, 108 108 const ast::TypeSubstitution * subs ) { … … 126 126 if ( closedVars.find( *inst ) == closedVars.end() ) { 127 127 return true; 128 } 129 else { 128 } else { 130 129 assertf(false, "closed: %s", inst->name.c_str()); 131 130 } -
src/InitTweak/FixInitNew.cpp
r92355883 r2a301ff 22 22 #include "AST/SymbolTable.hpp" 23 23 #include "AST/Type.hpp" 24 #include "CodeGen/GenType.h" // for genPrettyType 25 #include "CodeGen/OperatorTable.h" 26 #include "Common/PassVisitor.h" // for PassVisitor, WithStmtsToAdd 24 #include "CodeGen/OperatorTable.h" // for isConstructor, isCtorDtor, isD... 27 25 #include "Common/SemanticError.h" // for SemanticError 28 26 #include "Common/ToString.hpp" // for toCString … … 33 31 #include "ResolvExpr/Resolver.h" // for findVoidExpression 34 32 #include "ResolvExpr/Unify.h" // for typesCompatible 35 #include "SymTab/Autogen.h" // for genImplicitCall36 33 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 37 #include "SymTab/Indexer.h" // for Indexer38 #include "SymTab/Mangler.h" // for Mangler39 #include "SynTree/LinkageSpec.h" // for C, Spec, Cforall, isBuiltin40 #include "SynTree/Attribute.h" // for Attribute41 #include "SynTree/Constant.h" // for Constant42 #include "SynTree/Declaration.h" // for ObjectDecl, FunctionDecl, Decl...43 #include "SynTree/Expression.h" // for UniqueExpr, VariableExpr, Unty...44 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit45 #include "SynTree/Label.h" // for Label, operator<46 #include "SynTree/Mutator.h" // for mutateAll, Mutator, maybeMutate47 #include "SynTree/Statement.h" // for ExprStmt, CompoundStmt, Branch...48 #include "SynTree/Type.h" // for Type, Type::StorageClasses49 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution, operator<<50 #include "SynTree/DeclReplacer.h" // for DeclReplacer51 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept52 #include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy53 34 54 35 extern bool ctordtorp; // print all debug … … 61 42 62 43 namespace InitTweak { 44 63 45 namespace { 64 46 65 // Shallow copy the pointer list for return. 66 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) { 67 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) { 68 return inst->base->params; 69 } 70 if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) { 71 return inst->base->params; 72 } 73 return {}; 74 } 75 76 /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &). 77 ast::FunctionDecl * genDefaultFunc( 78 const CodeLocation loc, 79 const std::string fname, 80 const ast::Type * paramType, 81 bool maybePolymorphic = true) { 82 std::vector<ast::ptr<ast::TypeDecl>> typeParams; 83 if ( maybePolymorphic ) typeParams = getGenericParams( paramType ); 84 auto dstParam = new ast::ObjectDecl( loc, 85 "_dst", 86 new ast::ReferenceType( paramType ), 87 nullptr, 88 {}, 89 ast::Linkage::Cforall 47 // Shallow copy the pointer list for return. 48 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) { 49 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) { 50 return inst->base->params; 51 } 52 if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) { 53 return inst->base->params; 54 } 55 return {}; 56 } 57 58 /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &). 59 ast::FunctionDecl * genDefaultFunc( 60 const CodeLocation loc, 61 const std::string fname, 62 const ast::Type * paramType, 63 bool maybePolymorphic = true) { 64 std::vector<ast::ptr<ast::TypeDecl>> typeParams; 65 if ( maybePolymorphic ) typeParams = getGenericParams( paramType ); 66 auto dstParam = new ast::ObjectDecl( loc, 67 "_dst", 68 new ast::ReferenceType( paramType ), 69 nullptr, 70 {}, 71 ast::Linkage::Cforall 72 ); 73 return new ast::FunctionDecl( loc, 74 fname, 75 std::move(typeParams), 76 {dstParam}, 77 {}, 78 new ast::CompoundStmt(loc), 79 {}, 80 ast::Linkage::Cforall 81 ); 82 } 83 84 struct SelfAssignChecker { 85 void previsit( const ast::ApplicationExpr * appExpr ); 86 }; 87 88 struct StmtExprResult { 89 const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr ); 90 }; 91 92 /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which 93 /// function calls need their parameters to be copy constructed 94 struct InsertImplicitCalls : public ast::WithShortCircuiting { 95 const ast::Expr * postvisit( const ast::ApplicationExpr * appExpr ); 96 97 // only handles each UniqueExpr once 98 // if order of visit does not change, this should be safe 99 void previsit (const ast::UniqueExpr *); 100 101 std::unordered_set<decltype(ast::UniqueExpr::id)> visitedIds; 102 }; 103 104 /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr, 105 /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both 106 /// arguments and return value temporaries 107 struct ResolveCopyCtors final : public ast::WithGuards, public ast::WithStmtsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithVisitorRef<ResolveCopyCtors>, public ast::WithConstTranslationUnit { 108 const ast::Expr * postvisit( const ast::ImplicitCopyCtorExpr * impCpCtorExpr ); 109 const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr ); 110 const ast::UniqueExpr * previsit( const ast::UniqueExpr * unqExpr ); 111 112 /// handles distant mutations of environment manually. 113 /// WithConstTypeSubstitution cannot remember where the environment is from 114 115 /// MUST be called at start of overload previsit 116 void previsit( const ast::Expr * expr); 117 /// MUST be called at return of overload postvisit 118 const ast::Expr * postvisit(const ast::Expr * expr); 119 120 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 121 const ast::Expr * makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg = nullptr ); 122 /// true if type does not need to be copy constructed to ensure correctness 123 bool skipCopyConstruct( const ast::Type * type ); 124 ast::ptr< ast::Expr > copyConstructArg( const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal ); 125 ast::Expr * destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ); 126 private: 127 /// hack to implement WithTypeSubstitution while conforming to mutation safety. 128 ast::TypeSubstitution * env = nullptr; 129 bool envModified = false; 130 }; 131 132 /// collects constructed object decls - used as a base class 133 struct ObjDeclCollector : public ast::WithGuards, public ast::WithShortCircuiting { 134 // use ordered data structure to maintain ordering for set_difference and for consistent error messages 135 typedef std::list< const ast::ObjectDecl * > ObjectSet; 136 void previsit( const ast::CompoundStmt *compoundStmt ); 137 void previsit( const ast::DeclStmt *stmt ); 138 139 // don't go into other functions 140 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 141 142 protected: 143 ObjectSet curVars; 144 }; 145 146 // debug 147 template<typename ObjectSet> 148 struct PrintSet { 149 PrintSet( const ObjectSet & objs ) : objs( objs ) {} 150 const ObjectSet & objs; 151 }; 152 template<typename ObjectSet> 153 PrintSet<ObjectSet> printSet( const ObjectSet & objs ) { return PrintSet<ObjectSet>( objs ); } 154 template<typename ObjectSet> 155 std::ostream & operator<<( std::ostream & out, const PrintSet<ObjectSet> & set) { 156 out << "{ "; 157 for ( auto & obj : set.objs ) { 158 out << obj->name << ", " ; 159 } // for 160 out << " }"; 161 return out; 162 } 163 164 struct LabelFinder final : public ObjDeclCollector { 165 typedef std::map< std::string, ObjectSet > LabelMap; 166 // map of Label -> live variables at that label 167 LabelMap vars; 168 169 typedef ObjDeclCollector Parent; 170 using Parent::previsit; 171 void previsit( const ast::Stmt * stmt ); 172 173 void previsit( const ast::CompoundStmt *compoundStmt ); 174 void previsit( const ast::DeclStmt *stmt ); 175 }; 176 177 /// insert destructor calls at the appropriate places. must happen before CtorInit nodes are removed 178 /// (currently by FixInit) 179 struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> { 180 typedef std::list< ObjectDecl * > OrderedDecls; 181 typedef std::list< OrderedDecls > OrderedDeclsStack; 182 183 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 184 185 typedef ObjDeclCollector Parent; 186 using Parent::previsit; 187 188 void previsit( const ast::FunctionDecl * funcDecl ); 189 190 void previsit( const ast::BranchStmt * stmt ); 191 private: 192 void handleGoto( const ast::BranchStmt * stmt ); 193 194 ast::Pass<LabelFinder> & finder; 195 LabelFinder::LabelMap & labelVars; 196 OrderedDeclsStack reverseDeclOrder; 197 }; 198 199 /// expand each object declaration to use its constructor after it is declared. 200 struct FixInit : public ast::WithStmtsToAdd<> { 201 static void fixInitializers( ast::TranslationUnit &translationUnit ); 202 203 const ast::DeclWithType * postvisit( const ast::ObjectDecl *objDecl ); 204 205 std::list< ast::ptr< ast::Decl > > staticDtorDecls; 206 }; 207 208 /// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors 209 /// for any member that is missing a corresponding ctor/dtor call. 210 /// error if a member is used before constructed 211 struct GenStructMemberCalls final : public ast::WithGuards, public ast::WithShortCircuiting, public ast::WithSymbolTable, public ast::WithVisitorRef<GenStructMemberCalls>, public ast::WithConstTranslationUnit { 212 void previsit( const ast::FunctionDecl * funcDecl ); 213 const ast::DeclWithType * postvisit( const ast::FunctionDecl * funcDecl ); 214 215 void previsit( const ast::MemberExpr * memberExpr ); 216 void previsit( const ast::ApplicationExpr * appExpr ); 217 218 /// Note: this post mutate used to be in a separate visitor. If this pass breaks, one place to examine is whether it is 219 /// okay for this part of the recursion to occur alongside the rest. 220 const ast::Expr * postvisit( const ast::UntypedExpr * expr ); 221 222 SemanticErrorException errors; 223 private: 224 template< typename... Params > 225 void emit( CodeLocation, const Params &... params ); 226 227 ast::FunctionDecl * function = nullptr; 228 std::set< const ast::DeclWithType * > unhandled; 229 std::map< const ast::DeclWithType *, CodeLocation > usedUninit; 230 const ast::ObjectDecl * thisParam = nullptr; 231 bool isCtor = false; // true if current function is a constructor 232 const ast::StructDecl * structDecl = nullptr; 233 }; 234 235 /// expands ConstructorExpr nodes into comma expressions, using a temporary for the first argument 236 struct FixCtorExprs final : public ast::WithDeclsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithConstTranslationUnit { 237 const ast::Expr * postvisit( const ast::ConstructorExpr * ctorExpr ); 238 }; 239 240 /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places. 241 struct SplitExpressions : public ast::WithShortCircuiting { 242 ast::Stmt * postvisit( const ast::ExprStmt * stmt ); 243 void previsit( const ast::TupleAssignExpr * expr ); 244 }; 245 246 /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk 247 /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration 248 const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) { 249 const CodeLocation loc = input->location; 250 // unwrap implicit statement wrapper 251 // Statement * dtor = input; 252 assert( input ); 253 // std::list< const ast::Expr * > matches; 254 auto matches = collectCtorDtorCalls( input ); 255 256 if ( dynamic_cast< const ast::ExprStmt * >( input ) ) { 257 // only one destructor call in the expression 258 if ( matches.size() == 1 ) { 259 auto func = getFunction( matches.front() ); 260 assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() ); 261 262 // cleanup argument must be a function, not an object (including function pointer) 263 if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) { 264 if ( dtorFunc->type->forall.empty() ) { 265 // simple case where the destructor is a monomorphic function call - can simply 266 // use that function as the cleanup function. 267 return func; 268 } 269 } 270 } 271 } 272 273 // otherwise the cleanup is more complicated - need to build a single argument cleanup function that 274 // wraps the more complicated code. 275 static UniqueName dtorNamer( "__cleanup_dtor" ); 276 std::string name = dtorNamer.newName(); 277 ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false ); 278 stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) ); 279 280 // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter. 281 const ast::ObjectDecl * thisParam = getParamThis( dtorFunc ); 282 const ast::Expr * replacement = new ast::VariableExpr( loc, thisParam ); 283 284 auto base = replacement->result->stripReferences(); 285 if ( dynamic_cast< const ast::ArrayType * >( base ) || dynamic_cast< const ast::TupleType * > ( base ) ) { 286 // need to cast away reference for array types, since the destructor is generated without the reference type, 287 // and for tuple types since tuple indexing does not work directly on a reference 288 replacement = new ast::CastExpr( replacement, base ); 289 } 290 auto dtor = ast::DeclReplacer::replace( input, ast::DeclReplacer::ExprMap{ std::make_pair( objDecl, replacement ) } ); 291 auto mutStmts = dtorFunc->stmts.get_and_mutate(); 292 mutStmts->push_back(strict_dynamic_cast<const ast::Stmt *>( dtor )); 293 dtorFunc->stmts = mutStmts; 294 295 return dtorFunc; 296 } 297 298 void FixInit::fixInitializers( ast::TranslationUnit & translationUnit ) { 299 ast::Pass<FixInit> fixer; 300 301 // can't use mutateAll, because need to insert declarations at top-level 302 // can't use DeclMutator, because sometimes need to insert IfStmt, etc. 303 SemanticErrorException errors; 304 for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) { 305 try { 306 // maybeAccept( *i, fixer ); translationUnit should never contain null 307 *i = (*i)->accept(fixer); 308 translationUnit.decls.splice( i, fixer.core.staticDtorDecls ); 309 } catch( SemanticErrorException &e ) { 310 errors.append( e ); 311 } // try 312 } // for 313 if ( ! errors.isEmpty() ) { 314 throw errors; 315 } // if 316 } 317 318 const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) { 319 // we might loose the result expression here so add a pointer to trace back 320 assert( stmtExpr->result ); 321 const ast::Type * result = stmtExpr->result; 322 if ( ! result->isVoid() ) { 323 auto mutExpr = mutate(stmtExpr); 324 const ast::CompoundStmt * body = mutExpr->stmts; 325 assert( ! body->kids.empty() ); 326 mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>(); 327 return mutExpr; 328 } 329 return stmtExpr; 330 } 331 332 ast::Stmt * SplitExpressions::postvisit( const ast::ExprStmt * stmt ) { 333 // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed 334 // in the correct places 335 ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } ); 336 return ret; 337 } 338 339 void SplitExpressions::previsit( const ast::TupleAssignExpr * ) { 340 // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions 341 visit_children = false; 342 } 343 344 // Relatively simple structural comparison for expressions, needed to determine 345 // if two expressions are "the same" (used to determine if self assignment occurs) 346 struct StructuralChecker { 347 // Strip all casts and then dynamic_cast. 348 template<typename T> 349 static const T * cast( const ast::Expr * expr ) { 350 // this might be too permissive. It's possible that only particular casts are relevant. 351 while ( auto cast = dynamic_cast< const ast::CastExpr * >( expr ) ) { 352 expr = cast->arg; 353 } 354 return dynamic_cast< const T * >( expr ); 355 } 356 357 void previsit( const ast::Expr * ) { 358 // anything else does not qualify 359 result = false; 360 } 361 362 // ignore casts 363 void previsit( const ast::CastExpr * ) {} 364 365 void previsit( const ast::MemberExpr * memExpr ) { 366 if ( auto otherMember = cast< ast::MemberExpr >( other ) ) { 367 if ( otherMember->member == memExpr->member ) { 368 other = otherMember->aggregate; 369 return; 370 } 371 } 372 result = false; 373 } 374 375 void previsit( const ast::VariableExpr * varExpr ) { 376 if ( auto otherVar = cast< ast::VariableExpr >( other ) ) { 377 if ( otherVar->var == varExpr->var ) { 378 return; 379 } 380 } 381 result = false; 382 } 383 384 void previsit( const ast::AddressExpr * ) { 385 if ( auto addrExpr = cast< ast::AddressExpr >( other ) ) { 386 other = addrExpr->arg; 387 return; 388 } 389 result = false; 390 } 391 392 const ast::Expr * other; 393 bool result = true; 394 StructuralChecker( const ast::Expr * other ) : other(other) {} 395 }; 396 397 bool structurallySimilar( const ast::Expr * e1, const ast::Expr * e2 ) { 398 return ast::Pass<StructuralChecker>::read( e1, e2 ); 399 } 400 401 void SelfAssignChecker::previsit( const ast::ApplicationExpr * appExpr ) { 402 auto function = getFunction( appExpr ); 403 // Doesn't use isAssignment, because ?+=?, etc. should not count as self-assignment. 404 if ( function->name == "?=?" && appExpr->args.size() == 2 405 // Check for structural similarity (same variable use, ignore casts, etc. 406 // (but does not look too deeply, anything looking like a function is off limits). 407 && structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) { 408 SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) ); 409 } 410 } 411 412 const ast::Expr * InsertImplicitCalls::postvisit( const ast::ApplicationExpr * appExpr ) { 413 if ( auto function = appExpr->func.as<ast::VariableExpr>() ) { 414 if ( function->var->linkage.is_builtin ) { 415 // optimization: don't need to copy construct in order to call intrinsic functions 416 return appExpr; 417 } else if ( auto funcDecl = function->var.as<ast::DeclWithType>() ) { 418 auto ftype = dynamic_cast< const ast::FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) ); 419 assertf( ftype, "Function call without function type: %s", toString( funcDecl ).c_str() ); 420 if ( CodeGen::isConstructor( funcDecl->name ) && ftype->params.size() == 2 ) { 421 auto t1 = getPointerBase( ftype->params.front() ); 422 auto t2 = ftype->params.back(); 423 assert( t1 ); 424 425 if ( ResolvExpr::typesCompatible( t1, t2 ) ) { 426 // optimization: don't need to copy construct in order to call a copy constructor 427 return appExpr; 428 } // if 429 } else if ( CodeGen::isDestructor( funcDecl->name ) ) { 430 // correctness: never copy construct arguments to a destructor 431 return appExpr; 432 } // if 433 } // if 434 } // if 435 CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; ) 436 437 // wrap each function call so that it is easy to identify nodes that have to be copy constructed 438 ast::ptr<ast::TypeSubstitution> tmp = appExpr->env; 439 auto mutExpr = mutate(appExpr); 440 mutExpr->env = nullptr; 441 442 auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr ); 443 // Move the type substitution to the new top-level. The substitution 444 // is needed to obtain the type of temporary variables so that copy 445 // constructor calls can be resolved. 446 expr->env = tmp; 447 return expr; 448 } 449 450 void ResolveCopyCtors::previsit(const ast::Expr * expr) { 451 if ( nullptr == expr->env ) { 452 return; 453 } 454 GuardValue( env ) = expr->env->clone(); 455 GuardValue( envModified ) = false; 456 } 457 458 const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) { 459 // No local environment, skip. 460 if ( nullptr == expr->env ) { 461 return expr; 462 // Environment was modified, mutate and replace. 463 } else if ( envModified ) { 464 auto mutExpr = mutate(expr); 465 mutExpr->env = env; 466 return mutExpr; 467 // Environment was not mutated, delete the shallow copy before guard. 468 } else { 469 delete env; 470 return expr; 471 } 472 } 473 474 bool ResolveCopyCtors::skipCopyConstruct( const ast::Type * type ) { return ! isConstructable( type ); } 475 476 const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) { 477 assert( var ); 478 assert( var->isManaged() ); 479 assert( !cpArg || cpArg->isManaged() ); 480 // arrays are not copy constructed, so this should always be an ExprStmt 481 ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg ); 482 assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() ); 483 auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>(); 484 ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr 485 486 // resolve copy constructor 487 // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed 488 // (VariableExpr and already resolved expression) 489 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 490 ast::ptr<ast::Expr> resolved = ResolvExpr::findVoidExpression(untyped, { symtab, transUnit().global } ); 491 assert( resolved ); 492 if ( resolved->env ) { 493 // Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes. 494 env->add( *resolved->env ); 495 envModified = true; 496 auto mut = mutate(resolved.get()); 497 assertf(mut == resolved.get(), "newly resolved expression must be unique"); 498 mut->env = nullptr; 499 } // if 500 if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) { 501 // fix newly generated StmtExpr 502 previsit( assign->stmtExpr ); 503 } 504 return resolved.release(); 505 } 506 507 ast::ptr<ast::Expr> ResolveCopyCtors::copyConstructArg( 508 const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal ) 509 { 510 static UniqueName tempNamer("_tmp_cp"); 511 const CodeLocation loc = impCpCtorExpr->location; 512 // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; ) 513 assert( arg->result ); 514 ast::ptr<ast::Type> result = arg->result; 515 if ( skipCopyConstruct( result ) ) return arg; // skip certain non-copyable types 516 517 // type may involve type variables, so apply type substitution to get temporary variable's actual type, 518 // since result type may not be substituted (e.g., if the type does not appear in the parameter list) 519 // Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T). 520 521 // xxx - this originally mutates arg->result in place. is it correct? 522 assert( env ); 523 result = env->applyFree( result.get() ).node; 524 auto mutResult = result.get_and_mutate(); 525 mutResult->set_const(false); 526 527 auto mutArg = mutate(arg); 528 mutArg->result = mutResult; 529 530 ast::ptr<ast::Expr> guard = mutArg; 531 532 ast::ptr<ast::ObjectDecl> tmp = new ast::ObjectDecl(loc, "__tmp", mutResult, nullptr ); 533 534 // create and resolve copy constructor 535 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 536 auto cpCtor = makeCtorDtor( "?{}", tmp, mutArg ); 537 538 if ( auto appExpr = dynamic_cast< const ast::ApplicationExpr * >( cpCtor ) ) { 539 // if the chosen constructor is intrinsic, the copy is unnecessary, so 540 // don't create the temporary and don't call the copy constructor 541 auto function = appExpr->func.strict_as<ast::VariableExpr>(); 542 if ( function->var->linkage == ast::Linkage::Intrinsic ) { 543 // arguments that need to be boxed need a temporary regardless of whether the copy constructor is intrinsic, 544 // so that the object isn't changed inside of the polymorphic function 545 if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) { 546 // xxx - should arg->result be mutated? see comment above. 547 return guard; 548 } 549 } 550 } 551 552 // set a unique name for the temporary once it's certain the call is necessary 553 auto mut = tmp.get_and_mutate(); 554 assertf (mut == tmp, "newly created ObjectDecl must be unique"); 555 mut->name = tempNamer.newName(); 556 557 // replace argument to function call with temporary 558 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, tmp ) ); 559 arg = cpCtor; 560 return destructRet( tmp, arg ); 561 562 // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) ); 563 } 564 565 ast::Expr * ResolveCopyCtors::destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ) { 566 auto global = transUnit().global; 567 // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places 568 // check for existing cleanup attribute before adding another(?) 569 // need to add __Destructor for _tmp_cp variables as well 570 571 assertf( global.dtorStruct, "Destructor generation requires __Destructor definition." ); 572 assertf( global.dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." ); 573 assertf( global.dtorDestroy, "Destructor generation requires __destroy_Destructor." ); 574 575 const CodeLocation loc = ret->location; 576 577 // generate a __Destructor for ret that calls the destructor 578 auto res = makeCtorDtor( "^?{}", ret ); 579 auto dtor = mutate(res); 580 581 // if the chosen destructor is intrinsic, elide the generated dtor handler 582 if ( arg && isIntrinsicCallExpr( dtor ) ) { 583 return new ast::CommaExpr(loc, arg, new ast::VariableExpr(loc, ret ) ); 584 } 585 586 if ( ! dtor->env ) dtor->env = maybeClone( env ); 587 auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore ); 588 589 auto dtorStructType = new ast::StructInstType( global.dtorStruct ); 590 591 // what does this do??? 592 dtorStructType->params.push_back( new ast::TypeExpr(loc, new ast::VoidType() ) ); 593 594 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings 595 auto dtorFtype = new ast::FunctionType(); 596 dtorFtype->params.push_back( new ast::PointerType(new ast::VoidType( ) ) ); 597 auto dtorType = new ast::PointerType( dtorFtype ); 598 599 static UniqueName namer( "_ret_dtor" ); 600 auto retDtor = new ast::ObjectDecl(loc, namer.newName(), dtorStructType, new ast::ListInit(loc, { new ast::SingleInit(loc, ast::ConstantExpr::null(loc) ), new ast::SingleInit(loc, new ast::CastExpr( new ast::VariableExpr(loc, dtorFunc ), dtorType ) ) } ) ); 601 retDtor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, global.dtorDestroy ) } ) ); 602 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, retDtor ) ); 603 604 if ( arg ) { 605 auto member = new ast::MemberExpr(loc, global.dtorStruct->members.front().strict_as<ast::DeclWithType>(), new ast::VariableExpr(loc, retDtor ) ); 606 auto object = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, ret ) ), new ast::PointerType(new ast::VoidType() ) ); 607 ast::Expr * assign = createBitwiseAssignment( member, object ); 608 return new ast::CommaExpr(loc, new ast::CommaExpr(loc, arg, assign ), new ast::VariableExpr(loc, ret ) ); 609 } 610 return nullptr; 611 // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 612 } 613 614 const ast::Expr * ResolveCopyCtors::postvisit( const ast::ImplicitCopyCtorExpr *impCpCtorExpr ) { 615 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 616 617 ast::ApplicationExpr * appExpr = mutate(impCpCtorExpr->callExpr.get()); 618 const ast::ObjectDecl * returnDecl = nullptr; 619 const CodeLocation loc = appExpr->location; 620 621 // take each argument and attempt to copy construct it. 622 auto ftype = GenPoly::getFunctionType( appExpr->func->result ); 623 assert( ftype ); 624 auto & params = ftype->params; 625 auto iter = params.begin(); 626 for ( auto & arg : appExpr->args ) { 627 const ast::Type * formal = nullptr; 628 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments 629 // DeclarationWithType * param = *iter++; 630 formal = *iter++; 631 } 632 633 arg = copyConstructArg( arg, impCpCtorExpr, formal ); 634 } // for 635 636 // each return value from the call needs to be connected with an ObjectDecl at the call site, which is 637 // initialized with the return value and is destructed later 638 // xxx - handle named return values? 639 const ast::Type * result = appExpr->result; 640 if ( ! result->isVoid() ) { 641 static UniqueName retNamer("_tmp_cp_ret"); 642 auto subResult = env->apply( result ).node; 643 auto ret = new ast::ObjectDecl(loc, retNamer.newName(), subResult, nullptr ); 644 auto mutType = mutate(ret->type.get()); 645 mutType->set_const( false ); 646 ret->type = mutType; 647 returnDecl = ret; 648 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) ); 649 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 650 } // for 651 CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; ) 652 // ------------------------------------------------------ 653 654 CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; ) 655 656 // detach fields from wrapper node so that it can be deleted without deleting too much 657 658 // xxx - actual env might be somewhere else, need to keep invariant 659 660 // deletion of wrapper should be handled by pass template now 661 662 // impCpCtorExpr->callExpr = nullptr; 663 assert (appExpr->env == nullptr); 664 appExpr->env = impCpCtorExpr->env; 665 // std::swap( impCpCtorExpr->env, appExpr->env ); 666 // assert( impCpCtorExpr->env == nullptr ); 667 // delete impCpCtorExpr; 668 669 if ( returnDecl ) { 670 ast::Expr * assign = createBitwiseAssignment( new ast::VariableExpr(loc, returnDecl ), appExpr ); 671 if ( ! dynamic_cast< const ast::ReferenceType * >( result ) ) { 672 // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary 673 assign = destructRet( returnDecl, assign ); 674 assert(assign); 675 } else { 676 assign = new ast::CommaExpr(loc, assign, new ast::VariableExpr(loc, returnDecl ) ); 677 } 678 // move env from appExpr to retExpr 679 // std::swap( assign->env, appExpr->env ); 680 assign->env = appExpr->env; 681 // actual env is handled by common routine that replaces WithTypeSubstitution 682 return postvisit((const ast::Expr *)assign); 683 } else { 684 return postvisit((const ast::Expr *)appExpr); 685 } // if 686 } 687 688 const ast::StmtExpr * ResolveCopyCtors::previsit( const ast::StmtExpr * _stmtExpr ) { 689 // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression, 690 // since temporaries can be shared across sub-expressions, e.g. 691 // [A, A] f(); // decl 692 // g([A] x, [A] y); // decl 693 // g(f()); // call 694 // f is executed once, so the return temporary is shared across the tuple constructors for x and y. 695 // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added 696 // to the outer context, rather than inside of the statement expression. 697 698 // call the common routine that replaces WithTypeSubstitution 699 previsit((const ast::Expr *) _stmtExpr); 700 701 visit_children = false; 702 const CodeLocation loc = _stmtExpr->location; 703 704 assert( env ); 705 706 symtab.enterScope(); 707 // visit all statements 708 auto stmtExpr = mutate(_stmtExpr); 709 auto mutStmts = mutate(stmtExpr->stmts.get()); 710 711 auto & stmts = mutStmts->kids; 712 for ( auto & stmt : stmts ) { 713 stmt = stmt->accept( *visitor ); 714 } // for 715 stmtExpr->stmts = mutStmts; 716 symtab.leaveScope(); 717 718 assert( stmtExpr->result ); 719 // const ast::Type * result = stmtExpr->result; 720 if ( ! stmtExpr->result->isVoid() ) { 721 static UniqueName retNamer("_tmp_stmtexpr_ret"); 722 723 // result = result->clone(); 724 auto result = env->apply( stmtExpr->result.get() ).node; 725 if ( ! InitTweak::isConstructable( result ) ) { 726 // delete result; 727 return stmtExpr; 728 } 729 auto mutResult = result.get_and_mutate(); 730 mutResult->set_const(false); 731 732 // create variable that will hold the result of the stmt expr 733 auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr ); 734 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) ); 735 736 assertf( 737 stmtExpr->resultExpr, 738 "Statement-Expression should have a resulting expression at %s:%d", 739 stmtExpr->location.filename.c_str(), 740 stmtExpr->location.first_line 90 741 ); 91 return new ast::FunctionDecl( loc, 92 fname, 93 std::move(typeParams), 94 {dstParam}, 95 {}, 96 new ast::CompoundStmt(loc), 97 {}, 98 ast::Linkage::Cforall 99 ); 100 } 101 102 struct SelfAssignChecker { 103 void previsit( const ast::ApplicationExpr * appExpr ); 104 }; 105 106 struct StmtExprResult { 107 const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr ); 108 }; 109 110 /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which 111 /// function calls need their parameters to be copy constructed 112 struct InsertImplicitCalls : public ast::WithShortCircuiting { 113 const ast::Expr * postvisit( const ast::ApplicationExpr * appExpr ); 114 115 // only handles each UniqueExpr once 116 // if order of visit does not change, this should be safe 117 void previsit (const ast::UniqueExpr *); 118 119 std::unordered_set<decltype(ast::UniqueExpr::id)> visitedIds; 120 }; 121 122 /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr, 123 /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both 124 /// arguments and return value temporaries 125 struct ResolveCopyCtors final : public ast::WithGuards, public ast::WithStmtsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithVisitorRef<ResolveCopyCtors>, public ast::WithConstTranslationUnit { 126 const ast::Expr * postvisit( const ast::ImplicitCopyCtorExpr * impCpCtorExpr ); 127 const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr ); 128 const ast::UniqueExpr * previsit( const ast::UniqueExpr * unqExpr ); 129 130 /// handles distant mutations of environment manually. 131 /// WithConstTypeSubstitution cannot remember where the environment is from 132 133 /// MUST be called at start of overload previsit 134 void previsit( const ast::Expr * expr); 135 /// MUST be called at return of overload postvisit 136 const ast::Expr * postvisit(const ast::Expr * expr); 137 138 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 139 const ast::Expr * makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg = nullptr ); 140 /// true if type does not need to be copy constructed to ensure correctness 141 bool skipCopyConstruct( const ast::Type * type ); 142 ast::ptr< ast::Expr > copyConstructArg( const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal ); 143 ast::Expr * destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ); 144 private: 145 /// hack to implement WithTypeSubstitution while conforming to mutation safety. 146 ast::TypeSubstitution * env = nullptr; 147 bool envModified = false; 148 }; 149 150 /// collects constructed object decls - used as a base class 151 struct ObjDeclCollector : public ast::WithGuards, public ast::WithShortCircuiting { 152 // use ordered data structure to maintain ordering for set_difference and for consistent error messages 153 typedef std::list< const ast::ObjectDecl * > ObjectSet; 154 void previsit( const ast::CompoundStmt *compoundStmt ); 155 void previsit( const ast::DeclStmt *stmt ); 156 157 // don't go into other functions 158 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 159 160 protected: 161 ObjectSet curVars; 162 }; 163 164 // debug 165 template<typename ObjectSet> 166 struct PrintSet { 167 PrintSet( const ObjectSet & objs ) : objs( objs ) {} 168 const ObjectSet & objs; 169 }; 170 template<typename ObjectSet> 171 PrintSet<ObjectSet> printSet( const ObjectSet & objs ) { return PrintSet<ObjectSet>( objs ); } 172 template<typename ObjectSet> 173 std::ostream & operator<<( std::ostream & out, const PrintSet<ObjectSet> & set) { 174 out << "{ "; 175 for ( auto & obj : set.objs ) { 176 out << obj->name << ", " ; 177 } // for 178 out << " }"; 179 return out; 180 } 181 182 struct LabelFinder final : public ObjDeclCollector { 183 typedef std::map< std::string, ObjectSet > LabelMap; 184 // map of Label -> live variables at that label 185 LabelMap vars; 186 187 typedef ObjDeclCollector Parent; 188 using Parent::previsit; 189 void previsit( const ast::Stmt * stmt ); 190 191 void previsit( const ast::CompoundStmt *compoundStmt ); 192 void previsit( const ast::DeclStmt *stmt ); 193 }; 194 195 /// insert destructor calls at the appropriate places. must happen before CtorInit nodes are removed 196 /// (currently by FixInit) 197 struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> { 198 typedef std::list< ObjectDecl * > OrderedDecls; 199 typedef std::list< OrderedDecls > OrderedDeclsStack; 200 201 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 202 203 typedef ObjDeclCollector Parent; 204 using Parent::previsit; 205 206 void previsit( const ast::FunctionDecl * funcDecl ); 207 208 void previsit( const ast::BranchStmt * stmt ); 209 private: 210 void handleGoto( const ast::BranchStmt * stmt ); 211 212 ast::Pass<LabelFinder> & finder; 213 LabelFinder::LabelMap & labelVars; 214 OrderedDeclsStack reverseDeclOrder; 215 }; 216 217 /// expand each object declaration to use its constructor after it is declared. 218 struct FixInit : public ast::WithStmtsToAdd<> { 219 static void fixInitializers( ast::TranslationUnit &translationUnit ); 220 221 const ast::DeclWithType * postvisit( const ast::ObjectDecl *objDecl ); 222 223 std::list< ast::ptr< ast::Decl > > staticDtorDecls; 224 }; 225 226 /// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors 227 /// for any member that is missing a corresponding ctor/dtor call. 228 /// error if a member is used before constructed 229 struct GenStructMemberCalls final : public ast::WithGuards, public ast::WithShortCircuiting, public ast::WithSymbolTable, public ast::WithVisitorRef<GenStructMemberCalls>, public ast::WithConstTranslationUnit { 230 void previsit( const ast::FunctionDecl * funcDecl ); 231 const ast::DeclWithType * postvisit( const ast::FunctionDecl * funcDecl ); 232 233 void previsit( const ast::MemberExpr * memberExpr ); 234 void previsit( const ast::ApplicationExpr * appExpr ); 235 236 /// Note: this post mutate used to be in a separate visitor. If this pass breaks, one place to examine is whether it is 237 /// okay for this part of the recursion to occur alongside the rest. 238 const ast::Expr * postvisit( const ast::UntypedExpr * expr ); 239 240 SemanticErrorException errors; 241 private: 242 template< typename... Params > 243 void emit( CodeLocation, const Params &... params ); 244 245 ast::FunctionDecl * function = nullptr; 246 std::set< const ast::DeclWithType * > unhandled; 247 std::map< const ast::DeclWithType *, CodeLocation > usedUninit; 248 const ast::ObjectDecl * thisParam = nullptr; 249 bool isCtor = false; // true if current function is a constructor 250 const ast::StructDecl * structDecl = nullptr; 251 }; 252 253 /// expands ConstructorExpr nodes into comma expressions, using a temporary for the first argument 254 struct FixCtorExprs final : public ast::WithDeclsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithConstTranslationUnit { 255 const ast::Expr * postvisit( const ast::ConstructorExpr * ctorExpr ); 256 }; 257 258 /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places. 259 struct SplitExpressions : public ast::WithShortCircuiting { 260 ast::Stmt * postvisit( const ast::ExprStmt * stmt ); 261 void previsit( const ast::TupleAssignExpr * expr ); 262 }; 742 743 const ast::ExprStmt * last = stmtExpr->resultExpr; 744 // xxx - if this is non-unique, need to copy while making resultExpr ref 745 assertf(last->unique(), "attempt to modify weakly shared statement"); 746 auto mutLast = mutate(last); 747 // above assertion means in-place mutation is OK 748 try { 749 mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr ); 750 } catch(...) { 751 std::cerr << "*CFA internal error: "; 752 std::cerr << "can't resolve implicit constructor"; 753 std::cerr << " at " << stmtExpr->location.filename; 754 std::cerr << ":" << stmtExpr->location.first_line << std::endl; 755 756 abort(); 757 } 758 759 // add destructors after current statement 760 stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) ); 761 762 // must have a non-empty body, otherwise it wouldn't have a result 763 assert( ! stmts.empty() ); 764 765 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns 766 stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) ); 767 } // if 768 769 assert( stmtExpr->returnDecls.empty() ); 770 assert( stmtExpr->dtors.empty() ); 771 772 return stmtExpr; 773 } 774 775 // to prevent warnings ('_unq0' may be used uninitialized in this function), 776 // insert an appropriate zero initializer for UniqueExpr temporaries. 777 ast::Init * makeInit( const ast::Type * t, CodeLocation const & loc ) { 778 if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) { 779 // initizer for empty struct must be empty 780 if ( inst->base->members.empty() ) { 781 return new ast::ListInit( loc, {} ); 782 } 783 } else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) { 784 // initizer for empty union must be empty 785 if ( inst->base->members.empty() ) { 786 return new ast::ListInit( loc, {} ); 787 } 788 } 789 790 return new ast::ListInit( loc, { 791 new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ) 792 } ); 793 } 794 795 const ast::UniqueExpr * ResolveCopyCtors::previsit( const ast::UniqueExpr * unqExpr ) { 796 visit_children = false; 797 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated 798 static std::unordered_map< int, const ast::UniqueExpr * > unqMap; 799 auto mutExpr = mutate(unqExpr); 800 if ( ! unqMap.count( unqExpr->id ) ) { 801 // resolve expr and find its 802 803 auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>(); 804 // PassVisitor<ResolveCopyCtors> fixer; 805 806 mutExpr->expr = mutExpr->expr->accept( *visitor ); 807 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought 808 assert( unqExpr->result ); 809 if ( impCpCtorExpr ) { 810 auto comma = unqExpr->expr.strict_as<ast::CommaExpr>(); 811 auto var = comma->arg2.strict_as<ast::VariableExpr>(); 812 // note the variable used as the result from the call 813 mutExpr->var = var; 814 } else { 815 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression 816 mutExpr->object = new ast::ObjectDecl( mutExpr->location, toString("_unq", mutExpr->id), mutExpr->result, makeInit( mutExpr->result, mutExpr->location ) ); 817 mutExpr->var = new ast::VariableExpr( mutExpr->location, mutExpr->object ); 818 } 819 820 unqMap[mutExpr->id] = mutExpr; 821 } else { 822 // take data from other UniqueExpr to ensure consistency 823 // delete unqExpr->get_expr(); 824 mutExpr->expr = unqMap[mutExpr->id]->expr; 825 // delete unqExpr->result; 826 mutExpr->result = mutExpr->expr->result; 827 } 828 return mutExpr; 829 } 830 831 const ast::DeclWithType * FixInit::postvisit( const ast::ObjectDecl *_objDecl ) { 832 const CodeLocation loc = _objDecl->location; 833 834 // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit) 835 if ( ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>() ) { 836 auto objDecl = mutate(_objDecl); 837 838 // could this be non-unique? 839 if (objDecl != _objDecl) { 840 std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl; 841 } 842 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 843 assert( ! ctorInit->ctor || ! ctorInit->init ); 844 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 845 if ( objDecl->storage.is_static ) { 846 addDataSectionAttribute(objDecl); 847 // originally wanted to take advantage of gcc nested functions, but 848 // we get memory errors with this approach. To remedy this, the static 849 // variable is hoisted when the destructor needs to be called. 850 // 851 // generate: 852 // static T __objName_static_varN; 853 // void __objName_dtor_atexitN() { 854 // __dtor__...; 855 // } 856 // int f(...) { 857 // ... 858 // static bool __objName_uninitialized = true; 859 // if (__objName_uninitialized) { 860 // __ctor(__objName); 861 // __objName_uninitialized = false; 862 // atexit(__objName_dtor_atexitN); 863 // } 864 // ... 865 // } 866 867 static UniqueName dtorCallerNamer( "_dtor_atexit" ); 868 869 // static bool __objName_uninitialized = true 870 auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool ); 871 auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) ); 872 auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall); 873 isUninitializedVar->fixUniqueId(); 874 875 // __objName_uninitialized = false; 876 auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) ); 877 setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) ); 878 setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) ); 879 880 // generate body of if 881 auto initStmts = new ast::CompoundStmt(loc); 882 auto & body = initStmts->kids; 883 body.push_back( ctor ); 884 body.push_back( new ast::ExprStmt(loc, setTrue ) ); 885 886 // put it all together 887 auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 ); 888 stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) ); 889 stmtsToAddAfter.push_back( ifStmt ); 890 891 const ast::Stmt * dtor = ctorInit->dtor; 892 893 // these should be automatically managed once reassigned 894 // objDecl->set_init( nullptr ); 895 // ctorInit->set_ctor( nullptr ); 896 // ctorInit->set_dtor( nullptr ); 897 if ( dtor ) { 898 // if the object has a non-trivial destructor, have to 899 // hoist it and the object into the global space and 900 // call the destructor function with atexit. 901 902 // Statement * dtorStmt = dtor->clone(); 903 904 // void __objName_dtor_atexitN(...) {...} 905 ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C ); 906 dtorCaller->fixUniqueId(); 907 // dtorCaller->stmts->push_back( dtor ); 908 909 // atexit(dtor_atexit); 910 auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) ); 911 callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) ); 912 913 body.push_back( new ast::ExprStmt(loc, callAtexit ) ); 914 915 // hoist variable and dtor caller decls to list of decls that will be added into global scope 916 staticDtorDecls.push_back( objDecl ); 917 staticDtorDecls.push_back( dtorCaller ); 918 919 // need to rename object uniquely since it now appears 920 // at global scope and there could be multiple function-scoped 921 // static variables with the same name in different functions. 922 // Note: it isn't sufficient to modify only the mangleName, because 923 // then subsequent Indexer passes can choke on seeing the object's name 924 // if another object has the same name and type. An unfortunate side-effect 925 // of renaming the object is that subsequent NameExprs may fail to resolve, 926 // but there shouldn't be any remaining past this point. 927 static UniqueName staticNamer( "_static_var" ); 928 objDecl->name = objDecl->name + staticNamer.newName(); 929 objDecl->mangleName = Mangle::mangle( objDecl ); 930 objDecl->init = nullptr; 931 932 // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope 933 // create a new object which is never used 934 static UniqueName dummyNamer( "_dummy" ); 935 auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } ); 936 // delete ctorInit; 937 return dummy; 938 } else { 939 objDecl->init = nullptr; 940 return objDecl; 941 } 942 } else { 943 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor ); 944 auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>(); 945 const ast::ApplicationExpr * ctorCall = nullptr; 946 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) { 947 // clean up intrinsic copy constructor calls by making them into SingleInits 948 const ast::Expr * ctorArg = ctorCall->args.back(); 949 // ctorCall should be gone afterwards 950 auto mutArg = mutate(ctorArg); 951 mutArg->env = ctorCall->env; 952 // std::swap( ctorArg->env, ctorCall->env ); 953 objDecl->init = new ast::SingleInit(loc, mutArg ); 954 955 // ctorCall->args.pop_back(); 956 } else { 957 stmtsToAddAfter.push_back( ctor ); 958 objDecl->init = nullptr; 959 // ctorInit->ctor = nullptr; 960 } 961 962 const ast::Stmt * dtor = ctorInit->dtor; 963 if ( dtor ) { 964 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor ); 965 const ast::Stmt * dtorStmt = implicit->callStmt; 966 967 // don't need to call intrinsic dtor, because it does nothing, but 968 // non-intrinsic dtors must be called 969 if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) { 970 // set dtor location to the object's location for error messages 971 auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore ); 972 objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) ); 973 // ctorInit->dtor = nullptr; 974 } // if 975 } 976 } // if 977 } else if ( const ast::Init * init = ctorInit->init ) { 978 objDecl->init = init; 979 // ctorInit->init = nullptr; 980 } else { 981 // no constructor and no initializer, which is okay 982 objDecl->init = nullptr; 983 } // if 984 // delete ctorInit; 985 return objDecl; 986 } // if 987 return _objDecl; 988 } 989 990 void ObjDeclCollector::previsit( const ast::CompoundStmt * ) { 991 GuardValue( curVars ); 992 } 993 994 void ObjDeclCollector::previsit( const ast::DeclStmt * stmt ) { 995 // keep track of all variables currently in scope 996 if ( auto objDecl = stmt->decl.as<ast::ObjectDecl>() ) { 997 curVars.push_back( objDecl ); 998 } // if 999 } 1000 1001 void LabelFinder::previsit( const ast::Stmt * stmt ) { 1002 // for each label, remember the variables in scope at that label. 1003 for ( auto l : stmt->labels ) { 1004 vars[l] = curVars; 1005 } // for 1006 } 1007 1008 void LabelFinder::previsit( const ast::CompoundStmt * stmt ) { 1009 previsit( (const ast::Stmt *) stmt ); 1010 Parent::previsit( stmt ); 1011 } 1012 1013 void LabelFinder::previsit( const ast::DeclStmt * stmt ) { 1014 previsit( (const ast::Stmt *)stmt ); 1015 Parent::previsit( stmt ); 1016 } 1017 1018 void InsertDtors::previsit( const ast::FunctionDecl * funcDecl ) { 1019 // each function needs to have its own set of labels 1020 GuardValue( labelVars ); 1021 labelVars.clear(); 1022 // LabelFinder does not recurse into FunctionDecl, so need to visit 1023 // its children manually. 1024 if (funcDecl->type) funcDecl->type->accept(finder); 1025 // maybeAccept( funcDecl->type, finder ); 1026 if (funcDecl->stmts) funcDecl->stmts->accept(finder) ; 1027 1028 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion. 1029 } 1030 1031 // Handle break/continue/goto in the same manner as C++. Basic idea: any objects that are in scope at the 1032 // BranchStmt but not at the labelled (target) statement must be destructed. If there are any objects in scope 1033 // at the target location but not at the BranchStmt then those objects would be uninitialized so notify the user 1034 // of the error. See C++ Reference 6.6 Jump Statements for details. 1035 void InsertDtors::handleGoto( const ast::BranchStmt * stmt ) { 1036 // can't do anything for computed goto 1037 if ( stmt->computedTarget ) return; 1038 1039 assertf( stmt->target.name != "", "BranchStmt missing a label: %s", toString( stmt ).c_str() ); 1040 // S_L = lvars = set of objects in scope at label definition 1041 // S_G = curVars = set of objects in scope at goto statement 1042 ObjectSet & lvars = labelVars[ stmt->target ]; 1043 1044 DTOR_PRINT( 1045 std::cerr << "at goto label: " << stmt->target.name << std::endl; 1046 std::cerr << "S_G = " << printSet( curVars ) << std::endl; 1047 std::cerr << "S_L = " << printSet( lvars ) << std::endl; 1048 ) 1049 1050 1051 // std::set_difference requires that the inputs be sorted. 1052 lvars.sort(); 1053 curVars.sort(); 1054 1055 ObjectSet diff; 1056 // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty 1057 std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) ); 1058 DTOR_PRINT( 1059 std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl; 1060 ) 1061 if ( ! diff.empty() ) { 1062 SemanticError( stmt, std::string("jump to label '") + stmt->target.name + "' crosses initialization of " + (*diff.begin())->name + " " ); 1063 } // if 1064 } 1065 1066 void InsertDtors::previsit( const ast::BranchStmt * stmt ) { 1067 switch( stmt->kind ) { 1068 case ast::BranchStmt::Continue: 1069 case ast::BranchStmt::Break: 1070 // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should 1071 // always be empty), but it serves as a small sanity check. 1072 case ast::BranchStmt::Goto: 1073 handleGoto( stmt ); 1074 break; 1075 default: 1076 assert( false ); 1077 } // switch 1078 } 1079 1080 bool checkWarnings( const ast::FunctionDecl * funcDecl ) { 1081 // only check for warnings if the current function is a user-defined 1082 // constructor or destructor 1083 if ( ! funcDecl ) return false; 1084 if ( ! funcDecl->stmts ) return false; 1085 return CodeGen::isCtorDtor( funcDecl->name ) && ! funcDecl->linkage.is_overrideable; 1086 } 1087 1088 void GenStructMemberCalls::previsit( const ast::FunctionDecl * funcDecl ) { 1089 GuardValue( function ); 1090 GuardValue( unhandled ); 1091 GuardValue( usedUninit ); 1092 GuardValue( thisParam ); 1093 GuardValue( isCtor ); 1094 GuardValue( structDecl ); 1095 errors = SemanticErrorException(); // clear previous errors 1096 1097 // need to start with fresh sets 1098 unhandled.clear(); 1099 usedUninit.clear(); 1100 1101 function = mutate(funcDecl); 1102 // could this be non-unique? 1103 if (function != funcDecl) { 1104 std::cerr << "GenStructMemberCalls: non-unique FunctionDecl " << funcDecl->location << funcDecl->name << std::endl; 1105 } 1106 1107 isCtor = CodeGen::isConstructor( function->name ); 1108 if ( checkWarnings( function ) ) { 1109 // const ast::FunctionType * type = function->type; 1110 // assert( ! type->params.empty() ); 1111 thisParam = function->params.front().strict_as<ast::ObjectDecl>(); 1112 auto thisType = getPointerBase( thisParam->get_type() ); 1113 auto structType = dynamic_cast< const ast::StructInstType * >( thisType ); 1114 if ( structType ) { 1115 structDecl = structType->base; 1116 for ( auto & member : structDecl->members ) { 1117 if ( auto field = member.as<ast::ObjectDecl>() ) { 1118 // record all of the struct type's members that need to be constructed or 1119 // destructed by the end of the function 1120 unhandled.insert( field ); 1121 } 1122 } 1123 } 1124 } 1125 } 1126 1127 const ast::DeclWithType * GenStructMemberCalls::postvisit( const ast::FunctionDecl * funcDecl ) { 1128 // remove the unhandled objects from usedUninit, because a call is inserted 1129 // to handle them - only objects that are later constructed are used uninitialized. 1130 std::map< const ast::DeclWithType *, CodeLocation > diff; 1131 // need the comparator since usedUninit and unhandled have different types 1132 struct comp_t { 1133 typedef decltype(usedUninit)::value_type usedUninit_t; 1134 typedef decltype(unhandled)::value_type unhandled_t; 1135 bool operator()(usedUninit_t x, unhandled_t y) { return x.first < y; } 1136 bool operator()(unhandled_t x, usedUninit_t y) { return x < y.first; } 1137 } comp; 1138 std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ), comp ); 1139 for ( auto p : diff ) { 1140 auto member = p.first; 1141 auto loc = p.second; 1142 // xxx - make error message better by also tracking the location that the object is constructed at? 1143 emit( loc, "in ", function->name, ", field ", member->name, " used before being constructed" ); 1144 } 1145 1146 const CodeLocation loc = funcDecl->location; 1147 1148 if ( ! unhandled.empty() ) { 1149 auto mutStmts = function->stmts.get_and_mutate(); 1150 // need to explicitly re-add function parameters to the indexer in order to resolve copy constructors 1151 auto guard = makeFuncGuard( [this]() { symtab.enterScope(); }, [this]() { symtab.leaveScope(); } ); 1152 symtab.addFunction( function ); 1153 auto global = transUnit().global; 1154 1155 // need to iterate through members in reverse in order for 1156 // ctor/dtor statements to come out in the right order 1157 for ( auto & member : reverseIterate( structDecl->members ) ) { 1158 auto field = member.as<ast::ObjectDecl>(); 1159 // skip non-DWT members 1160 if ( ! field ) continue; 1161 // skip non-constructable members 1162 if ( ! tryConstruct( field ) ) continue; 1163 // skip handled members 1164 if ( ! unhandled.count( field ) ) continue; 1165 1166 // insert and resolve default/copy constructor call for each field that's unhandled 1167 // std::list< const ast::Stmt * > stmt; 1168 ast::Expr * arg2 = nullptr; 1169 if ( function->name == "?{}" && isCopyFunction( function ) ) { 1170 // if copy ctor, need to pass second-param-of-this-function.field 1171 // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters(); 1172 assert( function->params.size() == 2 ); 1173 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) ); 1174 } 1175 InitExpander_new srcParam( arg2 ); 1176 // cast away reference type and construct field. 1177 ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences()); 1178 ast::Expr * memberDest = new ast::MemberExpr(funcDecl->location, field, thisExpr ); 1179 ast::ptr<ast::Stmt> callStmt = SymTab::genImplicitCall( srcParam, memberDest, loc, function->name, field, static_cast<SymTab::LoopDirection>(isCtor) ); 1180 1181 if ( callStmt ) { 1182 // auto & callStmt = stmt.front(); 1183 1184 try { 1185 callStmt = callStmt->accept( *visitor ); 1186 if ( isCtor ) { 1187 mutStmts->push_front( callStmt ); 1188 } else { // TODO: don't generate destructor function/object for intrinsic calls 1189 // destructor statements should be added at the end 1190 // function->get_statements()->push_back( callStmt ); 1191 1192 // Optimization: do not need to call intrinsic destructors on members 1193 if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue; 1194 1195 // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A }; 1196 std::list< ast::ptr<ast::Stmt> > stmtsToAdd; 1197 1198 static UniqueName memberDtorNamer = { "__memberDtor" }; 1199 assertf( global.dtorStruct, "builtin __Destructor not found." ); 1200 assertf( global.dtorDestroy, "builtin __destroy_Destructor not found." ); 1201 1202 ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) ); 1203 ast::Expr * dtorExpr = new ast::VariableExpr(loc, getDtorFunc( thisParam, callStmt, stmtsToAdd ) ); 1204 1205 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings 1206 auto dtorFtype = new ast::FunctionType(); 1207 dtorFtype->params.emplace_back( new ast::PointerType( new ast::VoidType() ) ); 1208 auto dtorType = new ast::PointerType( dtorFtype ); 1209 1210 auto destructor = new ast::ObjectDecl(loc, memberDtorNamer.newName(), new ast::StructInstType( global.dtorStruct ), new ast::ListInit(loc, { new ast::SingleInit(loc, thisExpr ), new ast::SingleInit(loc, new ast::CastExpr( dtorExpr, dtorType ) ) } ) ); 1211 destructor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr( loc, global.dtorDestroy ) } ) ); 1212 mutStmts->push_front( new ast::DeclStmt(loc, destructor ) ); 1213 mutStmts->kids.splice( mutStmts->kids.begin(), stmtsToAdd ); 1214 } 1215 } catch ( SemanticErrorException & error ) { 1216 emit( funcDecl->location, "in ", function->name , ", field ", field->name, " not explicitly ", isCtor ? "constructed" : "destructed", " and no ", isCtor ? "default constructor" : "destructor", " found" ); 1217 } 1218 } 1219 } 1220 function->stmts = mutStmts; 1221 } 1222 if (! errors.isEmpty()) { 1223 throw errors; 1224 } 1225 // return funcDecl; 1226 return function; 1227 } 1228 1229 /// true if expr is effectively just the 'this' parameter 1230 bool isThisExpression( const ast::Expr * expr, const ast::DeclWithType * thisParam ) { 1231 // TODO: there are more complicated ways to pass 'this' to a constructor, e.g. &*, *&, etc. 1232 if ( auto varExpr = dynamic_cast< const ast::VariableExpr * >( expr ) ) { 1233 return varExpr->var == thisParam; 1234 } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * > ( expr ) ) { 1235 return isThisExpression( castExpr->arg, thisParam ); 1236 } 1237 return false; 1238 } 1239 1240 /// returns a MemberExpr if expr is effectively just member access on the 'this' parameter, else nullptr 1241 const ast::MemberExpr * isThisMemberExpr( const ast::Expr * expr, const ast::DeclWithType * thisParam ) { 1242 if ( auto memberExpr = dynamic_cast< const ast::MemberExpr * >( expr ) ) { 1243 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) { 1244 return memberExpr; 1245 } 1246 } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) { 1247 return isThisMemberExpr( castExpr->arg, thisParam ); 1248 } 1249 return nullptr; 1250 } 1251 1252 void GenStructMemberCalls::previsit( const ast::ApplicationExpr * appExpr ) { 1253 if ( ! checkWarnings( function ) ) { 1254 visit_children = false; 1255 return; 1256 } 1257 1258 std::string fname = getFunctionName( appExpr ); 1259 if ( fname == function->name ) { 1260 // call to same kind of function 1261 const ast::Expr * firstParam = appExpr->args.front(); 1262 1263 if ( isThisExpression( firstParam, thisParam ) ) { 1264 // if calling another constructor on thisParam, assume that function handles 1265 // all members - if it doesn't a warning will appear in that function. 1266 unhandled.clear(); 1267 } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) { 1268 // if first parameter is a member expression on the this parameter, 1269 // then remove the member from unhandled set. 1270 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) { 1271 unhandled.erase( memberExpr->member ); 1272 } 1273 } 1274 } 1275 } 1276 1277 void GenStructMemberCalls::previsit( const ast::MemberExpr * memberExpr ) { 1278 if ( ! checkWarnings( function ) || ! isCtor ) { 1279 visit_children = false; 1280 return; 1281 } 1282 1283 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) { 1284 if ( unhandled.count( memberExpr->member ) ) { 1285 // emit a warning because a member was used before it was constructed 1286 usedUninit.insert( { memberExpr->member, memberExpr->location } ); 1287 } 1288 } 1289 } 1290 1291 template< typename... Params > 1292 void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) { 1293 SemanticErrorException err( loc, toString( params... ) ); 1294 errors.append( err ); 1295 } 1296 1297 const ast::Expr * GenStructMemberCalls::postvisit( const ast::UntypedExpr * untypedExpr ) { 1298 // xxx - functions returning ast::ptr seems wrong... 1299 auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } ); 1300 return res.release(); 1301 } 1302 1303 void InsertImplicitCalls::previsit(const ast::UniqueExpr * unqExpr) { 1304 if (visitedIds.count(unqExpr->id)) visit_children = false; 1305 else visitedIds.insert(unqExpr->id); 1306 } 1307 1308 const ast::Expr * FixCtorExprs::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1309 const CodeLocation loc = ctorExpr->location; 1310 static UniqueName tempNamer( "_tmp_ctor_expr" ); 1311 // xxx - is the size check necessary? 1312 assert( ctorExpr->result && ctorExpr->result->size() == 1 ); 1313 1314 // xxx - this can be TupleAssignExpr now. Need to properly handle this case. 1315 // take possession of expr and env 1316 ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>(); 1317 ast::ptr<ast::TypeSubstitution> env = ctorExpr->env; 1318 // ctorExpr->set_callExpr( nullptr ); 1319 // ctorExpr->set_env( nullptr ); 1320 1321 // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary. 1322 auto tmp = new ast::ObjectDecl(loc, tempNamer.newName(), callExpr->args.front()->result ); 1323 declsToAddBefore.push_back( tmp ); 1324 1325 // build assignment and replace constructor's first argument with new temporary 1326 auto mutCallExpr = callExpr.get_and_mutate(); 1327 const ast::Expr * firstArg = callExpr->args.front(); 1328 ast::Expr * assign = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ), { new ast::AddressExpr(loc, new ast::VariableExpr(loc, tmp ) ), new ast::AddressExpr( firstArg ) } ); 1329 firstArg = new ast::VariableExpr(loc, tmp ); 1330 mutCallExpr->args.front() = firstArg; 1331 1332 // resolve assignment and dispose of new env 1333 auto resolved = ResolvExpr::findVoidExpression( assign, { symtab, transUnit().global } ); 1334 auto mut = resolved.get_and_mutate(); 1335 assertf(resolved.get() == mut, "newly resolved expression must be unique"); 1336 mut->env = nullptr; 1337 1338 // for constructor expr: 1339 // T x; 1340 // x{}; 1341 // results in: 1342 // T x; 1343 // T & tmp; 1344 // &tmp = &x, ?{}(tmp), tmp 1345 ast::CommaExpr * commaExpr = new ast::CommaExpr(loc, resolved, new ast::CommaExpr(loc, mutCallExpr, new ast::VariableExpr(loc, tmp ) ) ); 1346 commaExpr->env = env; 1347 return commaExpr; 1348 } 1349 263 1350 } // namespace 264 1351 … … 293 1380 } 294 1381 295 namespace {296 /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk297 /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration298 const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) {299 const CodeLocation loc = input->location;300 // unwrap implicit statement wrapper301 // Statement * dtor = input;302 assert( input );303 // std::list< const ast::Expr * > matches;304 auto matches = collectCtorDtorCalls( input );305 306 if ( dynamic_cast< const ast::ExprStmt * >( input ) ) {307 // only one destructor call in the expression308 if ( matches.size() == 1 ) {309 auto func = getFunction( matches.front() );310 assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );311 312 // cleanup argument must be a function, not an object (including function pointer)313 if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {314 if ( dtorFunc->type->forall.empty() ) {315 // simple case where the destructor is a monomorphic function call - can simply316 // use that function as the cleanup function.317 return func;318 }319 }320 }321 }322 323 // otherwise the cleanup is more complicated - need to build a single argument cleanup function that324 // wraps the more complicated code.325 static UniqueName dtorNamer( "__cleanup_dtor" );326 std::string name = dtorNamer.newName();327 ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );328 stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );329 330 // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.331 const ast::ObjectDecl * thisParam = getParamThis( dtorFunc );332 const ast::Expr * replacement = new ast::VariableExpr( loc, thisParam );333 334 auto base = replacement->result->stripReferences();335 if ( dynamic_cast< const ast::ArrayType * >( base ) || dynamic_cast< const ast::TupleType * > ( base ) ) {336 // need to cast away reference for array types, since the destructor is generated without the reference type,337 // and for tuple types since tuple indexing does not work directly on a reference338 replacement = new ast::CastExpr( replacement, base );339 }340 auto dtor = ast::DeclReplacer::replace( input, ast::DeclReplacer::ExprMap{ std::make_pair( objDecl, replacement ) } );341 auto mutStmts = dtorFunc->stmts.get_and_mutate();342 mutStmts->push_back(strict_dynamic_cast<const ast::Stmt *>( dtor ));343 dtorFunc->stmts = mutStmts;344 345 return dtorFunc;346 }347 348 void FixInit::fixInitializers( ast::TranslationUnit & translationUnit ) {349 ast::Pass<FixInit> fixer;350 351 // can't use mutateAll, because need to insert declarations at top-level352 // can't use DeclMutator, because sometimes need to insert IfStmt, etc.353 SemanticErrorException errors;354 for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) {355 try {356 // maybeAccept( *i, fixer ); translationUnit should never contain null357 *i = (*i)->accept(fixer);358 translationUnit.decls.splice( i, fixer.core.staticDtorDecls );359 } catch( SemanticErrorException &e ) {360 errors.append( e );361 } // try362 } // for363 if ( ! errors.isEmpty() ) {364 throw errors;365 } // if366 }367 368 const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) {369 // we might loose the result expression here so add a pointer to trace back370 assert( stmtExpr->result );371 const ast::Type * result = stmtExpr->result;372 if ( ! result->isVoid() ) {373 auto mutExpr = mutate(stmtExpr);374 const ast::CompoundStmt * body = mutExpr->stmts;375 assert( ! body->kids.empty() );376 mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();377 return mutExpr;378 }379 return stmtExpr;380 }381 382 ast::Stmt * SplitExpressions::postvisit( const ast::ExprStmt * stmt ) {383 // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed384 // in the correct places385 ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } );386 return ret;387 }388 389 void SplitExpressions::previsit( const ast::TupleAssignExpr * ) {390 // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions391 visit_children = false;392 }393 394 // Relatively simple structural comparison for expressions, needed to determine395 // if two expressions are "the same" (used to determine if self assignment occurs)396 struct StructuralChecker {397 // Strip all casts and then dynamic_cast.398 template<typename T>399 static const T * cast( const ast::Expr * expr ) {400 // this might be too permissive. It's possible that only particular casts are relevant.401 while ( auto cast = dynamic_cast< const ast::CastExpr * >( expr ) ) {402 expr = cast->arg;403 }404 return dynamic_cast< const T * >( expr );405 }406 407 void previsit( const ast::Expr * ) {408 // anything else does not qualify409 result = false;410 }411 412 // ignore casts413 void previsit( const ast::CastExpr * ) {}414 415 void previsit( const ast::MemberExpr * memExpr ) {416 if ( auto otherMember = cast< ast::MemberExpr >( other ) ) {417 if ( otherMember->member == memExpr->member ) {418 other = otherMember->aggregate;419 return;420 }421 }422 result = false;423 }424 425 void previsit( const ast::VariableExpr * varExpr ) {426 if ( auto otherVar = cast< ast::VariableExpr >( other ) ) {427 if ( otherVar->var == varExpr->var ) {428 return;429 }430 }431 result = false;432 }433 434 void previsit( const ast::AddressExpr * ) {435 if ( auto addrExpr = cast< ast::AddressExpr >( other ) ) {436 other = addrExpr->arg;437 return;438 }439 result = false;440 }441 442 const ast::Expr * other;443 bool result = true;444 StructuralChecker( const ast::Expr * other ) : other(other) {}445 };446 447 bool structurallySimilar( const ast::Expr * e1, const ast::Expr * e2 ) {448 return ast::Pass<StructuralChecker>::read( e1, e2 );449 }450 451 void SelfAssignChecker::previsit( const ast::ApplicationExpr * appExpr ) {452 auto function = getFunction( appExpr );453 // Doesn't use isAssignment, because ?+=?, etc. should not count as self-assignment.454 if ( function->name == "?=?" && appExpr->args.size() == 2455 // Check for structural similarity (same variable use, ignore casts, etc.456 // (but does not look too deeply, anything looking like a function is off limits).457 && structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) {458 SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) );459 }460 }461 462 const ast::Expr * InsertImplicitCalls::postvisit( const ast::ApplicationExpr * appExpr ) {463 if ( auto function = appExpr->func.as<ast::VariableExpr>() ) {464 if ( function->var->linkage.is_builtin ) {465 // optimization: don't need to copy construct in order to call intrinsic functions466 return appExpr;467 } else if ( auto funcDecl = function->var.as<ast::DeclWithType>() ) {468 auto ftype = dynamic_cast< const ast::FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) );469 assertf( ftype, "Function call without function type: %s", toString( funcDecl ).c_str() );470 if ( CodeGen::isConstructor( funcDecl->name ) && ftype->params.size() == 2 ) {471 auto t1 = getPointerBase( ftype->params.front() );472 auto t2 = ftype->params.back();473 assert( t1 );474 475 if ( ResolvExpr::typesCompatible( t1, t2 ) ) {476 // optimization: don't need to copy construct in order to call a copy constructor477 return appExpr;478 } // if479 } else if ( CodeGen::isDestructor( funcDecl->name ) ) {480 // correctness: never copy construct arguments to a destructor481 return appExpr;482 } // if483 } // if484 } // if485 CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; )486 487 // wrap each function call so that it is easy to identify nodes that have to be copy constructed488 ast::ptr<ast::TypeSubstitution> tmp = appExpr->env;489 auto mutExpr = mutate(appExpr);490 mutExpr->env = nullptr;491 492 auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr );493 // Move the type substitution to the new top-level. The substitution494 // is needed to obtain the type of temporary variables so that copy495 // constructor calls can be resolved.496 expr->env = tmp;497 return expr;498 }499 500 void ResolveCopyCtors::previsit(const ast::Expr * expr) {501 if ( nullptr == expr->env ) {502 return;503 }504 GuardValue( env ) = expr->env->clone();505 GuardValue( envModified ) = false;506 }507 508 const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) {509 // No local environment, skip.510 if ( nullptr == expr->env ) {511 return expr;512 // Environment was modified, mutate and replace.513 } else if ( envModified ) {514 auto mutExpr = mutate(expr);515 mutExpr->env = env;516 return mutExpr;517 // Environment was not mutated, delete the shallow copy before guard.518 } else {519 delete env;520 return expr;521 }522 }523 524 bool ResolveCopyCtors::skipCopyConstruct( const ast::Type * type ) { return ! isConstructable( type ); }525 526 const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) {527 assert( var );528 assert( var->isManaged() );529 assert( !cpArg || cpArg->isManaged() );530 // arrays are not copy constructed, so this should always be an ExprStmt531 ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg );532 assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() );533 auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>();534 ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr535 536 // resolve copy constructor537 // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed538 // (VariableExpr and already resolved expression)539 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )540 ast::ptr<ast::Expr> resolved = ResolvExpr::findVoidExpression(untyped, { symtab, transUnit().global } );541 assert( resolved );542 if ( resolved->env ) {543 // Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes.544 env->add( *resolved->env );545 envModified = true;546 auto mut = mutate(resolved.get());547 assertf(mut == resolved.get(), "newly resolved expression must be unique");548 mut->env = nullptr;549 } // if550 if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) {551 // fix newly generated StmtExpr552 previsit( assign->stmtExpr );553 }554 return resolved.release();555 }556 557 ast::ptr<ast::Expr> ResolveCopyCtors::copyConstructArg(558 const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal )559 {560 static UniqueName tempNamer("_tmp_cp");561 const CodeLocation loc = impCpCtorExpr->location;562 // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )563 assert( arg->result );564 ast::ptr<ast::Type> result = arg->result;565 if ( skipCopyConstruct( result ) ) return arg; // skip certain non-copyable types566 567 // type may involve type variables, so apply type substitution to get temporary variable's actual type,568 // since result type may not be substituted (e.g., if the type does not appear in the parameter list)569 // Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T).570 571 // xxx - this originally mutates arg->result in place. is it correct?572 assert( env );573 result = env->applyFree( result.get() ).node;574 auto mutResult = result.get_and_mutate();575 mutResult->set_const(false);576 577 auto mutArg = mutate(arg);578 mutArg->result = mutResult;579 580 ast::ptr<ast::Expr> guard = mutArg;581 582 ast::ptr<ast::ObjectDecl> tmp = new ast::ObjectDecl(loc, "__tmp", mutResult, nullptr );583 584 // create and resolve copy constructor585 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )586 auto cpCtor = makeCtorDtor( "?{}", tmp, mutArg );587 588 if ( auto appExpr = dynamic_cast< const ast::ApplicationExpr * >( cpCtor ) ) {589 // if the chosen constructor is intrinsic, the copy is unnecessary, so590 // don't create the temporary and don't call the copy constructor591 auto function = appExpr->func.strict_as<ast::VariableExpr>();592 if ( function->var->linkage == ast::Linkage::Intrinsic ) {593 // arguments that need to be boxed need a temporary regardless of whether the copy constructor is intrinsic,594 // so that the object isn't changed inside of the polymorphic function595 if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) {596 // xxx - should arg->result be mutated? see comment above.597 return guard;598 }599 }600 }601 602 // set a unique name for the temporary once it's certain the call is necessary603 auto mut = tmp.get_and_mutate();604 assertf (mut == tmp, "newly created ObjectDecl must be unique");605 mut->name = tempNamer.newName();606 607 // replace argument to function call with temporary608 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, tmp ) );609 arg = cpCtor;610 return destructRet( tmp, arg );611 612 // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );613 }614 615 ast::Expr * ResolveCopyCtors::destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ) {616 auto global = transUnit().global;617 // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places618 // check for existing cleanup attribute before adding another(?)619 // need to add __Destructor for _tmp_cp variables as well620 621 assertf( global.dtorStruct, "Destructor generation requires __Destructor definition." );622 assertf( global.dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." );623 assertf( global.dtorDestroy, "Destructor generation requires __destroy_Destructor." );624 625 const CodeLocation loc = ret->location;626 627 // generate a __Destructor for ret that calls the destructor628 auto res = makeCtorDtor( "^?{}", ret );629 auto dtor = mutate(res);630 631 // if the chosen destructor is intrinsic, elide the generated dtor handler632 if ( arg && isIntrinsicCallExpr( dtor ) ) {633 return new ast::CommaExpr(loc, arg, new ast::VariableExpr(loc, ret ) );634 }635 636 if ( ! dtor->env ) dtor->env = maybeClone( env );637 auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore );638 639 auto dtorStructType = new ast::StructInstType( global.dtorStruct );640 641 // what does this do???642 dtorStructType->params.push_back( new ast::TypeExpr(loc, new ast::VoidType() ) );643 644 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings645 auto dtorFtype = new ast::FunctionType();646 dtorFtype->params.push_back( new ast::PointerType(new ast::VoidType( ) ) );647 auto dtorType = new ast::PointerType( dtorFtype );648 649 static UniqueName namer( "_ret_dtor" );650 auto retDtor = new ast::ObjectDecl(loc, namer.newName(), dtorStructType, new ast::ListInit(loc, { new ast::SingleInit(loc, ast::ConstantExpr::null(loc) ), new ast::SingleInit(loc, new ast::CastExpr( new ast::VariableExpr(loc, dtorFunc ), dtorType ) ) } ) );651 retDtor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, global.dtorDestroy ) } ) );652 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, retDtor ) );653 654 if ( arg ) {655 auto member = new ast::MemberExpr(loc, global.dtorStruct->members.front().strict_as<ast::DeclWithType>(), new ast::VariableExpr(loc, retDtor ) );656 auto object = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, ret ) ), new ast::PointerType(new ast::VoidType() ) );657 ast::Expr * assign = createBitwiseAssignment( member, object );658 return new ast::CommaExpr(loc, new ast::CommaExpr(loc, arg, assign ), new ast::VariableExpr(loc, ret ) );659 }660 return nullptr;661 // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );662 }663 664 const ast::Expr * ResolveCopyCtors::postvisit( const ast::ImplicitCopyCtorExpr *impCpCtorExpr ) {665 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )666 667 ast::ApplicationExpr * appExpr = mutate(impCpCtorExpr->callExpr.get());668 const ast::ObjectDecl * returnDecl = nullptr;669 const CodeLocation loc = appExpr->location;670 671 // take each argument and attempt to copy construct it.672 auto ftype = GenPoly::getFunctionType( appExpr->func->result );673 assert( ftype );674 auto & params = ftype->params;675 auto iter = params.begin();676 for ( auto & arg : appExpr->args ) {677 const ast::Type * formal = nullptr;678 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments679 // DeclarationWithType * param = *iter++;680 formal = *iter++;681 }682 683 arg = copyConstructArg( arg, impCpCtorExpr, formal );684 } // for685 686 // each return value from the call needs to be connected with an ObjectDecl at the call site, which is687 // initialized with the return value and is destructed later688 // xxx - handle named return values?689 const ast::Type * result = appExpr->result;690 if ( ! result->isVoid() ) {691 static UniqueName retNamer("_tmp_cp_ret");692 auto subResult = env->apply( result ).node;693 auto ret = new ast::ObjectDecl(loc, retNamer.newName(), subResult, nullptr );694 auto mutType = mutate(ret->type.get());695 mutType->set_const( false );696 ret->type = mutType;697 returnDecl = ret;698 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );699 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )700 } // for701 CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )702 // ------------------------------------------------------703 704 CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )705 706 // detach fields from wrapper node so that it can be deleted without deleting too much707 708 // xxx - actual env might be somewhere else, need to keep invariant709 710 // deletion of wrapper should be handled by pass template now711 712 // impCpCtorExpr->callExpr = nullptr;713 assert (appExpr->env == nullptr);714 appExpr->env = impCpCtorExpr->env;715 // std::swap( impCpCtorExpr->env, appExpr->env );716 // assert( impCpCtorExpr->env == nullptr );717 // delete impCpCtorExpr;718 719 if ( returnDecl ) {720 ast::Expr * assign = createBitwiseAssignment( new ast::VariableExpr(loc, returnDecl ), appExpr );721 if ( ! dynamic_cast< const ast::ReferenceType * >( result ) ) {722 // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary723 assign = destructRet( returnDecl, assign );724 assert(assign);725 } else {726 assign = new ast::CommaExpr(loc, assign, new ast::VariableExpr(loc, returnDecl ) );727 }728 // move env from appExpr to retExpr729 // std::swap( assign->env, appExpr->env );730 assign->env = appExpr->env;731 // actual env is handled by common routine that replaces WithTypeSubstitution732 return postvisit((const ast::Expr *)assign);733 } else {734 return postvisit((const ast::Expr *)appExpr);735 } // if736 }737 738 const ast::StmtExpr * ResolveCopyCtors::previsit( const ast::StmtExpr * _stmtExpr ) {739 // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,740 // since temporaries can be shared across sub-expressions, e.g.741 // [A, A] f(); // decl742 // g([A] x, [A] y); // decl743 // g(f()); // call744 // f is executed once, so the return temporary is shared across the tuple constructors for x and y.745 // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added746 // to the outer context, rather than inside of the statement expression.747 748 // call the common routine that replaces WithTypeSubstitution749 previsit((const ast::Expr *) _stmtExpr);750 751 visit_children = false;752 const CodeLocation loc = _stmtExpr->location;753 754 assert( env );755 756 symtab.enterScope();757 // visit all statements758 auto stmtExpr = mutate(_stmtExpr);759 auto mutStmts = mutate(stmtExpr->stmts.get());760 761 auto & stmts = mutStmts->kids;762 for ( auto & stmt : stmts ) {763 stmt = stmt->accept( *visitor );764 } // for765 stmtExpr->stmts = mutStmts;766 symtab.leaveScope();767 768 assert( stmtExpr->result );769 // const ast::Type * result = stmtExpr->result;770 if ( ! stmtExpr->result->isVoid() ) {771 static UniqueName retNamer("_tmp_stmtexpr_ret");772 773 // result = result->clone();774 auto result = env->apply( stmtExpr->result.get() ).node;775 if ( ! InitTweak::isConstructable( result ) ) {776 // delete result;777 return stmtExpr;778 }779 auto mutResult = result.get_and_mutate();780 mutResult->set_const(false);781 782 // create variable that will hold the result of the stmt expr783 auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );784 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );785 786 assertf(787 stmtExpr->resultExpr,788 "Statement-Expression should have a resulting expression at %s:%d",789 stmtExpr->location.filename.c_str(),790 stmtExpr->location.first_line791 );792 793 const ast::ExprStmt * last = stmtExpr->resultExpr;794 // xxx - if this is non-unique, need to copy while making resultExpr ref795 assertf(last->unique(), "attempt to modify weakly shared statement");796 auto mutLast = mutate(last);797 // above assertion means in-place mutation is OK798 try {799 mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );800 } catch(...) {801 std::cerr << "*CFA internal error: ";802 std::cerr << "can't resolve implicit constructor";803 std::cerr << " at " << stmtExpr->location.filename;804 std::cerr << ":" << stmtExpr->location.first_line << std::endl;805 806 abort();807 }808 809 // add destructors after current statement810 stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );811 812 // must have a non-empty body, otherwise it wouldn't have a result813 assert( ! stmts.empty() );814 815 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns816 stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );817 } // if818 819 assert( stmtExpr->returnDecls.empty() );820 assert( stmtExpr->dtors.empty() );821 822 return stmtExpr;823 }824 825 // to prevent warnings ('_unq0' may be used uninitialized in this function),826 // insert an appropriate zero initializer for UniqueExpr temporaries.827 ast::Init * makeInit( const ast::Type * t, CodeLocation const & loc ) {828 if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {829 // initizer for empty struct must be empty830 if ( inst->base->members.empty() ) {831 return new ast::ListInit( loc, {} );832 }833 } else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {834 // initizer for empty union must be empty835 if ( inst->base->members.empty() ) {836 return new ast::ListInit( loc, {} );837 }838 }839 840 return new ast::ListInit( loc, {841 new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) )842 } );843 }844 845 const ast::UniqueExpr * ResolveCopyCtors::previsit( const ast::UniqueExpr * unqExpr ) {846 visit_children = false;847 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated848 static std::unordered_map< int, const ast::UniqueExpr * > unqMap;849 auto mutExpr = mutate(unqExpr);850 if ( ! unqMap.count( unqExpr->id ) ) {851 // resolve expr and find its852 853 auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>();854 // PassVisitor<ResolveCopyCtors> fixer;855 856 mutExpr->expr = mutExpr->expr->accept( *visitor );857 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought858 assert( unqExpr->result );859 if ( impCpCtorExpr ) {860 auto comma = unqExpr->expr.strict_as<ast::CommaExpr>();861 auto var = comma->arg2.strict_as<ast::VariableExpr>();862 // note the variable used as the result from the call863 mutExpr->var = var;864 } else {865 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression866 mutExpr->object = new ast::ObjectDecl( mutExpr->location, toString("_unq", mutExpr->id), mutExpr->result, makeInit( mutExpr->result, mutExpr->location ) );867 mutExpr->var = new ast::VariableExpr( mutExpr->location, mutExpr->object );868 }869 870 unqMap[mutExpr->id] = mutExpr;871 } else {872 // take data from other UniqueExpr to ensure consistency873 // delete unqExpr->get_expr();874 mutExpr->expr = unqMap[mutExpr->id]->expr;875 // delete unqExpr->result;876 mutExpr->result = mutExpr->expr->result;877 }878 return mutExpr;879 }880 881 const ast::DeclWithType * FixInit::postvisit( const ast::ObjectDecl *_objDecl ) {882 const CodeLocation loc = _objDecl->location;883 884 // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit)885 if ( ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>() ) {886 auto objDecl = mutate(_objDecl);887 888 // could this be non-unique?889 if (objDecl != _objDecl) {890 std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;891 }892 // a decision should have been made by the resolver, so ctor and init are not both non-NULL893 assert( ! ctorInit->ctor || ! ctorInit->init );894 if ( const ast::Stmt * ctor = ctorInit->ctor ) {895 if ( objDecl->storage.is_static ) {896 addDataSectionAttribute(objDecl);897 // originally wanted to take advantage of gcc nested functions, but898 // we get memory errors with this approach. To remedy this, the static899 // variable is hoisted when the destructor needs to be called.900 //901 // generate:902 // static T __objName_static_varN;903 // void __objName_dtor_atexitN() {904 // __dtor__...;905 // }906 // int f(...) {907 // ...908 // static bool __objName_uninitialized = true;909 // if (__objName_uninitialized) {910 // __ctor(__objName);911 // __objName_uninitialized = false;912 // atexit(__objName_dtor_atexitN);913 // }914 // ...915 // }916 917 static UniqueName dtorCallerNamer( "_dtor_atexit" );918 919 // static bool __objName_uninitialized = true920 auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );921 auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );922 auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);923 isUninitializedVar->fixUniqueId();924 925 // __objName_uninitialized = false;926 auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );927 setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );928 setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );929 930 // generate body of if931 auto initStmts = new ast::CompoundStmt(loc);932 auto & body = initStmts->kids;933 body.push_back( ctor );934 body.push_back( new ast::ExprStmt(loc, setTrue ) );935 936 // put it all together937 auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );938 stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );939 stmtsToAddAfter.push_back( ifStmt );940 941 const ast::Stmt * dtor = ctorInit->dtor;942 943 // these should be automatically managed once reassigned944 // objDecl->set_init( nullptr );945 // ctorInit->set_ctor( nullptr );946 // ctorInit->set_dtor( nullptr );947 if ( dtor ) {948 // if the object has a non-trivial destructor, have to949 // hoist it and the object into the global space and950 // call the destructor function with atexit.951 952 // Statement * dtorStmt = dtor->clone();953 954 // void __objName_dtor_atexitN(...) {...}955 ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );956 dtorCaller->fixUniqueId();957 // dtorCaller->stmts->push_back( dtor );958 959 // atexit(dtor_atexit);960 auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );961 callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );962 963 body.push_back( new ast::ExprStmt(loc, callAtexit ) );964 965 // hoist variable and dtor caller decls to list of decls that will be added into global scope966 staticDtorDecls.push_back( objDecl );967 staticDtorDecls.push_back( dtorCaller );968 969 // need to rename object uniquely since it now appears970 // at global scope and there could be multiple function-scoped971 // static variables with the same name in different functions.972 // Note: it isn't sufficient to modify only the mangleName, because973 // then subsequent Indexer passes can choke on seeing the object's name974 // if another object has the same name and type. An unfortunate side-effect975 // of renaming the object is that subsequent NameExprs may fail to resolve,976 // but there shouldn't be any remaining past this point.977 static UniqueName staticNamer( "_static_var" );978 objDecl->name = objDecl->name + staticNamer.newName();979 objDecl->mangleName = Mangle::mangle( objDecl );980 objDecl->init = nullptr;981 982 // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope983 // create a new object which is never used984 static UniqueName dummyNamer( "_dummy" );985 auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );986 // delete ctorInit;987 return dummy;988 } else {989 objDecl->init = nullptr;990 return objDecl;991 }992 } else {993 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );994 auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();995 const ast::ApplicationExpr * ctorCall = nullptr;996 if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {997 // clean up intrinsic copy constructor calls by making them into SingleInits998 const ast::Expr * ctorArg = ctorCall->args.back();999 // ctorCall should be gone afterwards1000 auto mutArg = mutate(ctorArg);1001 mutArg->env = ctorCall->env;1002 // std::swap( ctorArg->env, ctorCall->env );1003 objDecl->init = new ast::SingleInit(loc, mutArg );1004 1005 // ctorCall->args.pop_back();1006 } else {1007 stmtsToAddAfter.push_back( ctor );1008 objDecl->init = nullptr;1009 // ctorInit->ctor = nullptr;1010 }1011 1012 const ast::Stmt * dtor = ctorInit->dtor;1013 if ( dtor ) {1014 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );1015 const ast::Stmt * dtorStmt = implicit->callStmt;1016 1017 // don't need to call intrinsic dtor, because it does nothing, but1018 // non-intrinsic dtors must be called1019 if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {1020 // set dtor location to the object's location for error messages1021 auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );1022 objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );1023 // ctorInit->dtor = nullptr;1024 } // if1025 }1026 } // if1027 } else if ( const ast::Init * init = ctorInit->init ) {1028 objDecl->init = init;1029 // ctorInit->init = nullptr;1030 } else {1031 // no constructor and no initializer, which is okay1032 objDecl->init = nullptr;1033 } // if1034 // delete ctorInit;1035 return objDecl;1036 } // if1037 return _objDecl;1038 }1039 1040 void ObjDeclCollector::previsit( const ast::CompoundStmt * ) {1041 GuardValue( curVars );1042 }1043 1044 void ObjDeclCollector::previsit( const ast::DeclStmt * stmt ) {1045 // keep track of all variables currently in scope1046 if ( auto objDecl = stmt->decl.as<ast::ObjectDecl>() ) {1047 curVars.push_back( objDecl );1048 } // if1049 }1050 1051 void LabelFinder::previsit( const ast::Stmt * stmt ) {1052 // for each label, remember the variables in scope at that label.1053 for ( auto l : stmt->labels ) {1054 vars[l] = curVars;1055 } // for1056 }1057 1058 void LabelFinder::previsit( const ast::CompoundStmt * stmt ) {1059 previsit( (const ast::Stmt *) stmt );1060 Parent::previsit( stmt );1061 }1062 1063 void LabelFinder::previsit( const ast::DeclStmt * stmt ) {1064 previsit( (const ast::Stmt *)stmt );1065 Parent::previsit( stmt );1066 }1067 1068 1069 void InsertDtors::previsit( const ast::FunctionDecl * funcDecl ) {1070 // each function needs to have its own set of labels1071 GuardValue( labelVars );1072 labelVars.clear();1073 // LabelFinder does not recurse into FunctionDecl, so need to visit1074 // its children manually.1075 if (funcDecl->type) funcDecl->type->accept(finder);1076 // maybeAccept( funcDecl->type, finder );1077 if (funcDecl->stmts) funcDecl->stmts->accept(finder) ;1078 1079 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.1080 }1081 1082 // Handle break/continue/goto in the same manner as C++. Basic idea: any objects that are in scope at the1083 // BranchStmt but not at the labelled (target) statement must be destructed. If there are any objects in scope1084 // at the target location but not at the BranchStmt then those objects would be uninitialized so notify the user1085 // of the error. See C++ Reference 6.6 Jump Statements for details.1086 void InsertDtors::handleGoto( const ast::BranchStmt * stmt ) {1087 // can't do anything for computed goto1088 if ( stmt->computedTarget ) return;1089 1090 assertf( stmt->target.name != "", "BranchStmt missing a label: %s", toString( stmt ).c_str() );1091 // S_L = lvars = set of objects in scope at label definition1092 // S_G = curVars = set of objects in scope at goto statement1093 ObjectSet & lvars = labelVars[ stmt->target ];1094 1095 DTOR_PRINT(1096 std::cerr << "at goto label: " << stmt->target.name << std::endl;1097 std::cerr << "S_G = " << printSet( curVars ) << std::endl;1098 std::cerr << "S_L = " << printSet( lvars ) << std::endl;1099 )1100 1101 1102 // std::set_difference requires that the inputs be sorted.1103 lvars.sort();1104 curVars.sort();1105 1106 ObjectSet diff;1107 // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty1108 std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) );1109 DTOR_PRINT(1110 std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl;1111 )1112 if ( ! diff.empty() ) {1113 SemanticError( stmt, std::string("jump to label '") + stmt->target.name + "' crosses initialization of " + (*diff.begin())->name + " " );1114 } // if1115 }1116 1117 void InsertDtors::previsit( const ast::BranchStmt * stmt ) {1118 switch( stmt->kind ) {1119 case ast::BranchStmt::Continue:1120 case ast::BranchStmt::Break:1121 // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should1122 // always be empty), but it serves as a small sanity check.1123 case ast::BranchStmt::Goto:1124 handleGoto( stmt );1125 break;1126 default:1127 assert( false );1128 } // switch1129 }1130 1131 bool checkWarnings( const ast::FunctionDecl * funcDecl ) {1132 // only check for warnings if the current function is a user-defined1133 // constructor or destructor1134 if ( ! funcDecl ) return false;1135 if ( ! funcDecl->stmts ) return false;1136 return CodeGen::isCtorDtor( funcDecl->name ) && ! funcDecl->linkage.is_overrideable;1137 }1138 1139 void GenStructMemberCalls::previsit( const ast::FunctionDecl * funcDecl ) {1140 GuardValue( function );1141 GuardValue( unhandled );1142 GuardValue( usedUninit );1143 GuardValue( thisParam );1144 GuardValue( isCtor );1145 GuardValue( structDecl );1146 errors = SemanticErrorException(); // clear previous errors1147 1148 // need to start with fresh sets1149 unhandled.clear();1150 usedUninit.clear();1151 1152 function = mutate(funcDecl);1153 // could this be non-unique?1154 if (function != funcDecl) {1155 std::cerr << "GenStructMemberCalls: non-unique FunctionDecl " << funcDecl->location << funcDecl->name << std::endl;1156 }1157 1158 isCtor = CodeGen::isConstructor( function->name );1159 if ( checkWarnings( function ) ) {1160 // const ast::FunctionType * type = function->type;1161 // assert( ! type->params.empty() );1162 thisParam = function->params.front().strict_as<ast::ObjectDecl>();1163 auto thisType = getPointerBase( thisParam->get_type() );1164 auto structType = dynamic_cast< const ast::StructInstType * >( thisType );1165 if ( structType ) {1166 structDecl = structType->base;1167 for ( auto & member : structDecl->members ) {1168 if ( auto field = member.as<ast::ObjectDecl>() ) {1169 // record all of the struct type's members that need to be constructed or1170 // destructed by the end of the function1171 unhandled.insert( field );1172 }1173 }1174 }1175 }1176 }1177 1178 const ast::DeclWithType * GenStructMemberCalls::postvisit( const ast::FunctionDecl * funcDecl ) {1179 // remove the unhandled objects from usedUninit, because a call is inserted1180 // to handle them - only objects that are later constructed are used uninitialized.1181 std::map< const ast::DeclWithType *, CodeLocation > diff;1182 // need the comparator since usedUninit and unhandled have different types1183 struct comp_t {1184 typedef decltype(usedUninit)::value_type usedUninit_t;1185 typedef decltype(unhandled)::value_type unhandled_t;1186 bool operator()(usedUninit_t x, unhandled_t y) { return x.first < y; }1187 bool operator()(unhandled_t x, usedUninit_t y) { return x < y.first; }1188 } comp;1189 std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ), comp );1190 for ( auto p : diff ) {1191 auto member = p.first;1192 auto loc = p.second;1193 // xxx - make error message better by also tracking the location that the object is constructed at?1194 emit( loc, "in ", function->name, ", field ", member->name, " used before being constructed" );1195 }1196 1197 const CodeLocation loc = funcDecl->location;1198 1199 if ( ! unhandled.empty() ) {1200 auto mutStmts = function->stmts.get_and_mutate();1201 // need to explicitly re-add function parameters to the indexer in order to resolve copy constructors1202 auto guard = makeFuncGuard( [this]() { symtab.enterScope(); }, [this]() { symtab.leaveScope(); } );1203 symtab.addFunction( function );1204 auto global = transUnit().global;1205 1206 // need to iterate through members in reverse in order for1207 // ctor/dtor statements to come out in the right order1208 for ( auto & member : reverseIterate( structDecl->members ) ) {1209 auto field = member.as<ast::ObjectDecl>();1210 // skip non-DWT members1211 if ( ! field ) continue;1212 // skip non-constructable members1213 if ( ! tryConstruct( field ) ) continue;1214 // skip handled members1215 if ( ! unhandled.count( field ) ) continue;1216 1217 // insert and resolve default/copy constructor call for each field that's unhandled1218 // std::list< const ast::Stmt * > stmt;1219 ast::Expr * arg2 = nullptr;1220 if ( function->name == "?{}" && isCopyFunction( function ) ) {1221 // if copy ctor, need to pass second-param-of-this-function.field1222 // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();1223 assert( function->params.size() == 2 );1224 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );1225 }1226 InitExpander_new srcParam( arg2 );1227 // cast away reference type and construct field.1228 ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences());1229 ast::Expr * memberDest = new ast::MemberExpr(funcDecl->location, field, thisExpr );1230 ast::ptr<ast::Stmt> callStmt = SymTab::genImplicitCall( srcParam, memberDest, loc, function->name, field, static_cast<SymTab::LoopDirection>(isCtor) );1231 1232 if ( callStmt ) {1233 // auto & callStmt = stmt.front();1234 1235 try {1236 callStmt = callStmt->accept( *visitor );1237 if ( isCtor ) {1238 mutStmts->push_front( callStmt );1239 } else { // TODO: don't generate destructor function/object for intrinsic calls1240 // destructor statements should be added at the end1241 // function->get_statements()->push_back( callStmt );1242 1243 // Optimization: do not need to call intrinsic destructors on members1244 if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;1245 1246 // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };1247 std::list< ast::ptr<ast::Stmt> > stmtsToAdd;1248 1249 static UniqueName memberDtorNamer = { "__memberDtor" };1250 assertf( global.dtorStruct, "builtin __Destructor not found." );1251 assertf( global.dtorDestroy, "builtin __destroy_Destructor not found." );1252 1253 ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) );1254 ast::Expr * dtorExpr = new ast::VariableExpr(loc, getDtorFunc( thisParam, callStmt, stmtsToAdd ) );1255 1256 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings1257 auto dtorFtype = new ast::FunctionType();1258 dtorFtype->params.emplace_back( new ast::PointerType( new ast::VoidType() ) );1259 auto dtorType = new ast::PointerType( dtorFtype );1260 1261 auto destructor = new ast::ObjectDecl(loc, memberDtorNamer.newName(), new ast::StructInstType( global.dtorStruct ), new ast::ListInit(loc, { new ast::SingleInit(loc, thisExpr ), new ast::SingleInit(loc, new ast::CastExpr( dtorExpr, dtorType ) ) } ) );1262 destructor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr( loc, global.dtorDestroy ) } ) );1263 mutStmts->push_front( new ast::DeclStmt(loc, destructor ) );1264 mutStmts->kids.splice( mutStmts->kids.begin(), stmtsToAdd );1265 }1266 } catch ( SemanticErrorException & error ) {1267 emit( funcDecl->location, "in ", function->name , ", field ", field->name, " not explicitly ", isCtor ? "constructed" : "destructed", " and no ", isCtor ? "default constructor" : "destructor", " found" );1268 }1269 }1270 }1271 function->stmts = mutStmts;1272 }1273 if (! errors.isEmpty()) {1274 throw errors;1275 }1276 // return funcDecl;1277 return function;1278 }1279 1280 /// true if expr is effectively just the 'this' parameter1281 bool isThisExpression( const ast::Expr * expr, const ast::DeclWithType * thisParam ) {1282 // TODO: there are more complicated ways to pass 'this' to a constructor, e.g. &*, *&, etc.1283 if ( auto varExpr = dynamic_cast< const ast::VariableExpr * >( expr ) ) {1284 return varExpr->var == thisParam;1285 } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * > ( expr ) ) {1286 return isThisExpression( castExpr->arg, thisParam );1287 }1288 return false;1289 }1290 1291 /// returns a MemberExpr if expr is effectively just member access on the 'this' parameter, else nullptr1292 const ast::MemberExpr * isThisMemberExpr( const ast::Expr * expr, const ast::DeclWithType * thisParam ) {1293 if ( auto memberExpr = dynamic_cast< const ast::MemberExpr * >( expr ) ) {1294 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {1295 return memberExpr;1296 }1297 } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {1298 return isThisMemberExpr( castExpr->arg, thisParam );1299 }1300 return nullptr;1301 }1302 1303 void GenStructMemberCalls::previsit( const ast::ApplicationExpr * appExpr ) {1304 if ( ! checkWarnings( function ) ) {1305 visit_children = false;1306 return;1307 }1308 1309 std::string fname = getFunctionName( appExpr );1310 if ( fname == function->name ) {1311 // call to same kind of function1312 const ast::Expr * firstParam = appExpr->args.front();1313 1314 if ( isThisExpression( firstParam, thisParam ) ) {1315 // if calling another constructor on thisParam, assume that function handles1316 // all members - if it doesn't a warning will appear in that function.1317 unhandled.clear();1318 } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {1319 // if first parameter is a member expression on the this parameter,1320 // then remove the member from unhandled set.1321 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {1322 unhandled.erase( memberExpr->member );1323 }1324 }1325 }1326 }1327 1328 void GenStructMemberCalls::previsit( const ast::MemberExpr * memberExpr ) {1329 if ( ! checkWarnings( function ) || ! isCtor ) {1330 visit_children = false;1331 return;1332 }1333 1334 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {1335 if ( unhandled.count( memberExpr->member ) ) {1336 // emit a warning because a member was used before it was constructed1337 usedUninit.insert( { memberExpr->member, memberExpr->location } );1338 }1339 }1340 }1341 1342 template< typename... Params >1343 void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {1344 SemanticErrorException err( loc, toString( params... ) );1345 errors.append( err );1346 }1347 1348 const ast::Expr * GenStructMemberCalls::postvisit( const ast::UntypedExpr * untypedExpr ) {1349 // xxx - functions returning ast::ptr seems wrong...1350 auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );1351 return res.release();1352 }1353 1354 void InsertImplicitCalls::previsit(const ast::UniqueExpr * unqExpr) {1355 if (visitedIds.count(unqExpr->id)) visit_children = false;1356 else visitedIds.insert(unqExpr->id);1357 }1358 1359 const ast::Expr * FixCtorExprs::postvisit( const ast::ConstructorExpr * ctorExpr ) {1360 const CodeLocation loc = ctorExpr->location;1361 static UniqueName tempNamer( "_tmp_ctor_expr" );1362 // xxx - is the size check necessary?1363 assert( ctorExpr->result && ctorExpr->result->size() == 1 );1364 1365 // xxx - this can be TupleAssignExpr now. Need to properly handle this case.1366 // take possession of expr and env1367 ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>();1368 ast::ptr<ast::TypeSubstitution> env = ctorExpr->env;1369 // ctorExpr->set_callExpr( nullptr );1370 // ctorExpr->set_env( nullptr );1371 1372 // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.1373 auto tmp = new ast::ObjectDecl(loc, tempNamer.newName(), callExpr->args.front()->result );1374 declsToAddBefore.push_back( tmp );1375 1376 // build assignment and replace constructor's first argument with new temporary1377 auto mutCallExpr = callExpr.get_and_mutate();1378 const ast::Expr * firstArg = callExpr->args.front();1379 ast::Expr * assign = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ), { new ast::AddressExpr(loc, new ast::VariableExpr(loc, tmp ) ), new ast::AddressExpr( firstArg ) } );1380 firstArg = new ast::VariableExpr(loc, tmp );1381 mutCallExpr->args.front() = firstArg;1382 1383 // resolve assignment and dispose of new env1384 auto resolved = ResolvExpr::findVoidExpression( assign, { symtab, transUnit().global } );1385 auto mut = resolved.get_and_mutate();1386 assertf(resolved.get() == mut, "newly resolved expression must be unique");1387 mut->env = nullptr;1388 1389 // for constructor expr:1390 // T x;1391 // x{};1392 // results in:1393 // T x;1394 // T & tmp;1395 // &tmp = &x, ?{}(tmp), tmp1396 ast::CommaExpr * commaExpr = new ast::CommaExpr(loc, resolved, new ast::CommaExpr(loc, mutCallExpr, new ast::VariableExpr(loc, tmp ) ) );1397 commaExpr->env = env;1398 return commaExpr;1399 }1400 } // namespace1401 1382 } // namespace InitTweak 1402 1383 -
src/InitTweak/GenInit.cc
r92355883 r2a301ff 300 300 301 301 # warning Remove the _New suffix after the conversion is complete. 302 303 // Outer pass finds declarations, for their type could wrap a type that needs hoisting 302 304 struct HoistArrayDimension_NoResolve_New final : 303 305 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting, 304 306 public ast::WithGuards, public ast::WithConstTranslationUnit, 305 public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> { 306 void previsit( const ast::ObjectDecl * decl ); 307 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl ); 308 // Do not look for objects inside there declarations (and type). 309 void previsit( const ast::AggregateDecl * ) { visit_children = false; } 310 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; } 311 void previsit( const ast::FunctionType * ) { visit_children = false; } 312 313 const ast::Type * hoist( const ast::Type * type ); 307 public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New>, 308 public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> { 309 310 // Inner pass looks within a type, for a part that depends on an expression 311 struct HoistDimsFromTypes final : 312 public ast::WithShortCircuiting, public ast::WithGuards { 313 314 HoistArrayDimension_NoResolve_New * outer; 315 HoistDimsFromTypes( HoistArrayDimension_NoResolve_New * outer ) : outer(outer) {} 316 317 // Only intended for visiting through types. 318 // Tolerate, and short-circuit at, the dimension expression of an array type. 319 // (We'll operate on the dimension expression of an array type directly 320 // from the parent type, not by visiting through it) 321 // Look inside type exprs. 322 void previsit( const ast::Node * ) { 323 assert( false && "unsupported node type" ); 324 }; 325 const ast::Expr * allowedExpr = nullptr; 326 void previsit( const ast::Type * ) { 327 GuardValue( allowedExpr ) = nullptr; 328 } 329 void previsit( const ast::ArrayType * t ) { 330 GuardValue( allowedExpr ) = t->dimension.get(); 331 } 332 void previsit( const ast::PointerType * t ) { 333 GuardValue( allowedExpr ) = t->dimension.get(); 334 } 335 void previsit( const ast::TypeofType * t ) { 336 GuardValue( allowedExpr ) = t->expr.get(); 337 } 338 void previsit( const ast::Expr * e ) { 339 assert( e == allowedExpr && 340 "only expecting to visit exprs that are dimension exprs or typeof(-) inner exprs" ); 341 342 // Skip the tolerated expressions 343 visit_children = false; 344 } 345 void previsit( const ast::TypeExpr * ) {} 346 347 const ast::Type * postvisit( 348 const ast::ArrayType * arrayType ) { 349 static UniqueName dimensionName( "_array_dim" ); 350 351 if ( nullptr == arrayType->dimension ) { // if no dimension is given, don't presume to invent one 352 return arrayType; 353 } 354 355 // find size_t; use it as the type for a dim expr 356 ast::ptr<ast::Type> dimType = outer->transUnit().global.sizeType; 357 assert( dimType ); 358 add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) ); 359 360 // Special-case handling: leave the user's dimension expression alone 361 // - requires the user to have followed a careful convention 362 // - may apply to extremely simple applications, but only as windfall 363 // - users of advanced applications will be following the convention on purpose 364 // - CFA maintainers must protect the criteria against leaving too much alone 365 366 // Actual leave-alone cases following are conservative approximations of "cannot vary" 367 368 // Leave alone: literals and enum constants 369 if ( dynamic_cast< const ast::ConstantExpr * >( arrayType->dimension.get() ) ) { 370 return arrayType; 371 } 372 373 // Leave alone: direct use of an object declared to be const 374 const ast::NameExpr * dimn = dynamic_cast< const ast::NameExpr * >( arrayType->dimension.get() ); 375 if ( dimn ) { 376 std::vector<ast::SymbolTable::IdData> dimnDefs = outer->symtab.lookupId( dimn->name ); 377 if ( dimnDefs.size() == 1 ) { 378 const ast::DeclWithType * dimnDef = dimnDefs[0].id.get(); 379 assert( dimnDef && "symbol table binds a name to nothing" ); 380 const ast::ObjectDecl * dimOb = dynamic_cast< const ast::ObjectDecl * >( dimnDef ); 381 if( dimOb ) { 382 const ast::Type * dimTy = dimOb->type.get(); 383 assert( dimTy && "object declaration bearing no type" ); 384 // must not hoist some: size_t 385 // must hoist all: pointers and references 386 // the analysis is conservative; BasicType is a simple approximation 387 if ( dynamic_cast< const ast::BasicType * >( dimTy ) || 388 dynamic_cast< const ast::SueInstType<ast::EnumDecl> * >( dimTy ) ) { 389 if ( dimTy->is_const() ) { 390 // The dimension is certainly re-evaluable, giving the same answer each time. 391 // Our user might be hoping to write the array type in multiple places, having them unify. 392 // Leave the type alone. 393 394 // We believe the new criterion leaves less alone than the old criterion. 395 // Thus, the old criterion should have left the current case alone. 396 // Catch cases that weren't thought through. 397 assert( !Tuples::maybeImpure( arrayType->dimension ) ); 398 399 return arrayType; 400 } 401 }; 402 } 403 } 404 } 405 406 // Leave alone: any sizeof expression (answer cannot vary during current lexical scope) 407 const ast::SizeofExpr * sz = dynamic_cast< const ast::SizeofExpr * >( arrayType->dimension.get() ); 408 if ( sz ) { 409 return arrayType; 410 } 411 412 // General-case handling: change the array-type's dim expr (hoist the user-given content out of the type) 413 // - always safe 414 // - user-unnoticeable in common applications (benign noise in -CFA output) 415 // - may annoy a responsible user of advanced applications (but they can work around) 416 // - protects against misusing advanced features 417 // 418 // The hoist, by example, is: 419 // FROM USER: float a[ rand() ]; 420 // TO GCC: const size_t __len_of_a = rand(); float a[ __len_of_a ]; 421 422 ast::ObjectDecl * arrayDimension = new ast::ObjectDecl( 423 arrayType->dimension->location, 424 dimensionName.newName(), 425 dimType, 426 new ast::SingleInit( 427 arrayType->dimension->location, 428 arrayType->dimension 429 ) 430 ); 431 432 ast::ArrayType * mutType = ast::mutate( arrayType ); 433 mutType->dimension = new ast::VariableExpr( 434 arrayDimension->location, arrayDimension ); 435 outer->declsToAddBefore.push_back( arrayDimension ); 436 437 return mutType; 438 } // postvisit( const ast::ArrayType * ) 439 }; // struct HoistDimsFromTypes 314 440 315 441 ast::Storage::Classes storageClasses; 442 void previsit( 443 const ast::ObjectDecl * decl ) { 444 GuardValue( storageClasses ) = decl->storage; 445 } 446 447 const ast::DeclWithType * postvisit( 448 const ast::ObjectDecl * objectDecl ) { 449 450 if ( !isInFunction() || storageClasses.is_static ) { 451 return objectDecl; 452 } 453 454 const ast::Type * mid = objectDecl->type; 455 456 ast::Pass<HoistDimsFromTypes> hoist{this}; 457 const ast::Type * result = mid->accept( hoist ); 458 459 return mutate_field( objectDecl, &ast::ObjectDecl::type, result ); 460 } 316 461 }; 317 462 318 void HoistArrayDimension_NoResolve_New::previsit( 319 const ast::ObjectDecl * decl ) { 320 GuardValue( storageClasses ) = decl->storage; 321 } 322 323 const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit( 324 const ast::ObjectDecl * objectDecl ) { 325 return mutate_field( objectDecl, &ast::ObjectDecl::type, 326 hoist( objectDecl->type ) ); 327 } 328 329 const ast::Type * HoistArrayDimension_NoResolve_New::hoist( 330 const ast::Type * type ) { 331 static UniqueName dimensionName( "_array_dim" ); 332 333 if ( !isInFunction() || storageClasses.is_static ) { 334 return type; 335 } 336 337 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 338 if ( nullptr == arrayType->dimension ) { 339 return type; 340 } 341 342 if ( !Tuples::maybeImpure( arrayType->dimension ) ) { 343 return type; 344 } 345 346 ast::ptr<ast::Type> dimType = transUnit().global.sizeType; 347 assert( dimType ); 348 add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) ); 349 350 ast::ObjectDecl * arrayDimension = new ast::ObjectDecl( 351 arrayType->dimension->location, 352 dimensionName.newName(), 353 dimType, 354 new ast::SingleInit( 355 arrayType->dimension->location, 356 arrayType->dimension 357 ) 358 ); 359 360 ast::ArrayType * mutType = ast::mutate( arrayType ); 361 mutType->dimension = new ast::VariableExpr( 362 arrayDimension->location, arrayDimension ); 363 declsToAddBefore.push_back( arrayDimension ); 364 365 mutType->base = hoist( mutType->base ); 366 return mutType; 367 } 368 return type; 369 } 463 464 370 465 371 466 struct ReturnFixer_New final : -
src/InitTweak/InitTweak.cc
r92355883 r2a301ff 882 882 if (!assign) { 883 883 auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true); 884 assign = new ast::FunctionDecl(CodeLocation(), "?=?", { },884 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, 885 885 { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 886 886 new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))}, … … 891 891 dst = new ast::AddressExpr(dst); 892 892 } 893 } 894 else { 893 } else { 895 894 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 896 895 } … … 900 899 } 901 900 } 902 return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src}); 901 auto var = ast::VariableExpr::functionPointer(dst->location, assign); 902 auto app = new ast::ApplicationExpr(dst->location, var, {dst, src}); 903 // Skip the resolver, just set the result to the correct type. 904 app->result = ast::deepCopy( src->result ); 905 return app; 903 906 } 904 907 -
src/Parser/StatementNode.cc
r92355883 r2a301ff 10 10 // Author : Rodolfo G. Esteves 11 11 // Created On : Sat May 16 14:59:41 2015 12 // Last Modified By : Andrew Beach13 // Last Modified On : Tue Apr 11 10:16:00202314 // Update Count : 42 812 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Fri Aug 11 11:44:15 2023 14 // Update Count : 429 15 15 // 16 16 … … 361 361 362 362 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { 363 364 365 366 367 363 ast::WhenClause * clause = new ast::WhenClause( loc ); 364 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 365 clause->stmt = maybeMoveBuild( stmt ); 366 clause->target = maybeMoveBuild( targetExpr ); 367 return new ast::WaitUntilStmt::ClauseNode( clause ); 368 368 } 369 369 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) { 370 ast::WhenClause * clause = new ast::WhenClause( loc ); 371 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 372 clause->stmt = maybeMoveBuild( stmt ); 373 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause ); 374 } 375 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) { 376 ast::WhenClause * clause = new ast::WhenClause( loc ); 377 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 378 clause->stmt = maybeMoveBuild( stmt ); 379 clause->target = maybeMoveBuild( timeout ); 380 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause ); 370 ast::WhenClause * clause = new ast::WhenClause( loc ); 371 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 372 clause->stmt = maybeMoveBuild( stmt ); 373 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause ); 381 374 } 382 375 383 376 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) { 384 ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc ); 385 retStmt->predicateTree = root; 386 387 // iterative tree traversal 388 std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal 389 ast::WaitUntilStmt::ClauseNode * currNode = nullptr; 390 ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr; 391 ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout 392 nodeStack.push_back(root); 393 394 do { 395 currNode = nodeStack.back(); 396 nodeStack.pop_back(); // remove node since it will be processed 397 398 switch (currNode->op) { 399 case ast::WaitUntilStmt::ClauseNode::LEAF: 400 retStmt->clauses.push_back(currNode->leaf); 401 break; 402 case ast::WaitUntilStmt::ClauseNode::ELSE: 403 retStmt->else_stmt = currNode->leaf->stmt 404 ? ast::deepCopy( currNode->leaf->stmt ) 405 : nullptr; 406 407 retStmt->else_cond = currNode->leaf->when_cond 408 ? ast::deepCopy( currNode->leaf->when_cond ) 409 : nullptr; 410 411 delete currNode->leaf; 412 break; 413 case ast::WaitUntilStmt::ClauseNode::TIMEOUT: 414 retStmt->timeout_time = currNode->leaf->target 415 ? ast::deepCopy( currNode->leaf->target ) 416 : nullptr; 417 retStmt->timeout_stmt = currNode->leaf->stmt 418 ? ast::deepCopy( currNode->leaf->stmt ) 419 : nullptr; 420 retStmt->timeout_cond = currNode->leaf->when_cond 421 ? ast::deepCopy( currNode->leaf->when_cond ) 422 : nullptr; 423 424 delete currNode->leaf; 425 break; 426 default: 427 nodeStack.push_back( currNode->right ); // process right after left 428 nodeStack.push_back( currNode->left ); 429 430 // Cut else/timeout out of the tree 431 if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) { 432 if ( lastInternalNode ) 433 lastInternalNode->right = currNode->left; 434 else // if not set then root is LEFT_OR 435 retStmt->predicateTree = currNode->left; 436 437 currNode->left = nullptr; 438 cleanup = currNode; 439 } 440 441 lastInternalNode = currNode; 442 break; 443 } 444 } while ( !nodeStack.empty() ); 445 446 if ( cleanup ) delete cleanup; 447 448 return retStmt; 377 ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc ); 378 retStmt->predicateTree = root; 379 380 // iterative tree traversal 381 std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal 382 ast::WaitUntilStmt::ClauseNode * currNode = nullptr; 383 ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr; 384 ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout 385 nodeStack.push_back(root); 386 387 do { 388 currNode = nodeStack.back(); 389 nodeStack.pop_back(); // remove node since it will be processed 390 391 switch (currNode->op) { 392 case ast::WaitUntilStmt::ClauseNode::LEAF: 393 retStmt->clauses.push_back(currNode->leaf); 394 break; 395 case ast::WaitUntilStmt::ClauseNode::ELSE: 396 retStmt->else_stmt = currNode->leaf->stmt 397 ? ast::deepCopy( currNode->leaf->stmt ) 398 : nullptr; 399 retStmt->else_cond = currNode->leaf->when_cond 400 ? ast::deepCopy( currNode->leaf->when_cond ) 401 : nullptr; 402 403 delete currNode->leaf; 404 break; 405 case ast::WaitUntilStmt::ClauseNode::TIMEOUT: 406 retStmt->timeout_time = currNode->leaf->target 407 ? ast::deepCopy( currNode->leaf->target ) 408 : nullptr; 409 retStmt->timeout_stmt = currNode->leaf->stmt 410 ? ast::deepCopy( currNode->leaf->stmt ) 411 : nullptr; 412 retStmt->timeout_cond = currNode->leaf->when_cond 413 ? ast::deepCopy( currNode->leaf->when_cond ) 414 : nullptr; 415 416 delete currNode->leaf; 417 break; 418 default: 419 nodeStack.push_back( currNode->right ); // process right after left 420 nodeStack.push_back( currNode->left ); 421 422 // Cut else/timeout out of the tree 423 if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) { 424 if ( lastInternalNode ) 425 lastInternalNode->right = currNode->left; 426 else // if not set then root is LEFT_OR 427 retStmt->predicateTree = currNode->left; 428 429 currNode->left = nullptr; 430 cleanup = currNode; 431 } 432 433 lastInternalNode = currNode; 434 break; 435 } 436 } while ( !nodeStack.empty() ); 437 438 if ( cleanup ) delete cleanup; 439 440 return retStmt; 449 441 } 450 442 -
src/Parser/StatementNode.h
r92355883 r2a301ff 9 9 // Author : Andrew Beach 10 10 // Created On : Wed Apr 5 11:42:00 2023 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Apr 11 9:43:00202313 // Update Count : 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Aug 11 11:44:07 2023 13 // Update Count : 2 14 14 // 15 15 … … 102 102 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ); 103 103 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt ); 104 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );105 104 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root ); 106 105 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt ); -
src/Parser/TypedefTable.cc
r92355883 r2a301ff 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 15 08:27:24 202213 // Update Count : 27 512 // Last Modified On : Wed Jul 12 06:11:28 2023 13 // Update Count : 276 14 14 // 15 15 … … 17 17 #include "TypedefTable.h" 18 18 19 #include <cassert> 20 #include <string> 21 #include <iostream> 19 #include <cassert> // for assert 20 #include <string> // for string 21 #include <iostream> // for iostream 22 22 23 #include "ExpressionNode.h" 24 #include "ParserTypes.h" 25 #include "StatementNode.h" 23 #include "ExpressionNode.h" // for LabelNode 24 #include "ParserTypes.h" // for Token 25 #include "StatementNode.h" // for CondCtl, ForCtrl 26 26 // This (generated) header must come late as it is missing includes. 27 #include "parser.hh" 27 #include "parser.hh" // for IDENTIFIER, TYPEDEFname, TYPEGENname 28 28 29 29 using namespace std; … … 72 72 // "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the 73 73 // name is explicitly used. 74 void TypedefTable::makeTypedef( const string & name, int kind ) {74 void TypedefTable::makeTypedef( const string & name, int kind, const char * locn __attribute__((unused)) ) { 75 75 // Check for existence is necessary to handle: 76 76 // struct Fred {}; … … 80 80 // Fred(); 81 81 // } 82 debugPrint( cerr << "Make typedef at " << locn << " \"" << name << "\" as " << kindName( kind ) << " scope " << kindTable.currentScope() << endl ); 82 83 if ( ! typedefTable.exists( name ) ) { 83 84 typedefTable.addToEnclosingScope( name, kind, "MTD" ); … … 85 86 } // TypedefTable::makeTypedef 86 87 87 void TypedefTable::makeTypedef( const string & name ) { 88 return makeTypedef( name, TYPEDEFname ); 88 void TypedefTable::makeTypedef( const string & name, const char * locn __attribute__((unused)) ) { 89 debugPrint( cerr << "Make typedef at " << locn << " \"" << name << " scope " << kindTable.currentScope() << endl ); 90 return makeTypedef( name, TYPEDEFname, "makeTypede" ); 89 91 } // TypedefTable::makeTypedef 90 92 91 93 void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) { 92 94 KindTable::size_type scope = kindTable.currentScope(); 93 debugPrint( cerr << "Adding current at " << locn << " " << identifier <<" as " << kindName( kind ) << " scope " << scope << endl );95 debugPrint( cerr << "Adding current at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << endl ); 94 96 kindTable.insertAt( scope, identifier, kind ); 95 97 } // TypedefTable::addToScope … … 98 100 KindTable::size_type scope = kindTable.currentScope() - 1 - kindTable.getNote( kindTable.currentScope() - 1 ).level; 99 101 // size_type scope = level - kindTable.getNote( kindTable.currentScope() - 1 ).level; 100 debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier <<" as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );102 debugPrint( cerr << "Adding enclosing at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl ); 101 103 pair< KindTable::iterator, bool > ret = kindTable.insertAt( scope, identifier, kind ); 102 104 if ( ! ret.second ) ret.first->second = kind; // exists => update -
src/Parser/TypedefTable.h
r92355883 r2a301ff 10 10 // Created On : Sat May 16 15:24:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 15 08:06:37 202013 // Update Count : 11 712 // Last Modified On : Wed Jul 12 06:09:37 2023 13 // Update Count : 118 14 14 // 15 15 … … 21 21 22 22 class TypedefTable { 23 struct Note { size_t level; bool forall; }; 23 struct Note { 24 size_t level; 25 bool forall; 26 }; 24 27 typedef ScopedMap< std::string, int, Note > KindTable; 25 28 KindTable kindTable; … … 31 34 bool existsCurr( const std::string & identifier ) const; 32 35 int isKind( const std::string & identifier ) const; 33 void makeTypedef( const std::string & name, int kind );34 void makeTypedef( const std::string & name );36 void makeTypedef( const std::string & name, int kind, const char * ); 37 void makeTypedef( const std::string & name, const char * ); 35 38 void addToScope( const std::string & identifier, int kind, const char * ); 36 39 void addToEnclosingScope( const std::string & identifier, int kind, const char * ); -
src/Parser/parser.yy
r92355883 r2a301ff 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 17 18:53:24202313 // Update Count : 63 4712 // Last Modified On : Tue Jul 18 22:51:30 2023 13 // Update Count : 6391 14 14 // 15 15 … … 385 385 %type<str> string_literal_list 386 386 387 %type<enum_hiding> hide_opt 387 %type<enum_hiding> hide_opt visible_hide_opt 388 388 389 389 // expressions 390 390 %type<expr> constant 391 %type<expr> tuple 391 %type<expr> tuple tuple_expression_list 392 392 %type<oper> ptrref_operator unary_operator assignment_operator simple_assignment_operator compound_assignment_operator 393 393 %type<expr> primary_expression postfix_expression unary_expression 394 %type<expr> cast_expression_list 395 %type<expr> shift_expression 394 %type<expr> cast_expression_list cast_expression exponential_expression multiplicative_expression additive_expression 395 %type<expr> shift_expression relational_expression equality_expression 396 396 %type<expr> AND_expression exclusive_OR_expression inclusive_OR_expression 397 397 %type<expr> logical_AND_expression logical_OR_expression 398 398 %type<expr> conditional_expression constant_expression assignment_expression assignment_expression_opt 399 %type<expr> comma_expression 400 %type<expr> argument_expression_list_opt 399 %type<expr> comma_expression comma_expression_opt 400 %type<expr> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt 401 401 %type<ifctl> conditional_declaration 402 %type<forctl> for_control_expression 402 %type<forctl> for_control_expression for_control_expression_list 403 403 %type<oper> upupeq updown updowneq downupdowneq 404 404 %type<expr> subrange 405 405 %type<decl> asm_name_opt 406 %type<expr> asm_operands_opt 406 %type<expr> asm_operands_opt asm_operands_list asm_operand 407 407 %type<labels> label_list 408 408 %type<expr> asm_clobbers_list_opt … … 412 412 413 413 // statements 414 %type<stmt> statement 414 %type<stmt> statement labeled_statement compound_statement 415 415 %type<stmt> statement_decl statement_decl_list statement_list_nodecl 416 416 %type<stmt> selection_statement if_statement 417 %type<clause> switch_clause_list_opt 417 %type<clause> switch_clause_list_opt switch_clause_list 418 418 %type<expr> case_value 419 %type<clause> case_clause case_value_list case_label 419 %type<clause> case_clause case_value_list case_label case_label_list 420 420 %type<stmt> iteration_statement jump_statement 421 %type<stmt> expression_statement 421 %type<stmt> expression_statement asm_statement 422 422 %type<stmt> with_statement 423 423 %type<expr> with_clause_opt … … 427 427 %type<stmt> mutex_statement 428 428 %type<expr> when_clause when_clause_opt waitfor waituntil timeout 429 %type<stmt> waitfor_statement 429 %type<stmt> waitfor_statement waituntil_statement 430 430 %type<wfs> wor_waitfor_clause 431 431 %type<wucn> waituntil_clause wand_waituntil_clause wor_waituntil_clause … … 601 601 // around the list separator. 602 602 // 603 // int f( forall(T) T (*f1) T , forall( S ) S (*f2)( S ) );603 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 604 604 // push pop push pop 605 605 … … 689 689 // | RESUME '(' comma_expression ')' compound_statement 690 690 // { SemanticError( yylloc, "Resume expression is currently unimplemented." ); $$ = nullptr; } 691 | IDENTIFIER IDENTIFIER // invalid syntax rule s691 | IDENTIFIER IDENTIFIER // invalid syntax rule 692 692 { IdentifierBeforeIdentifier( *$1.str, *$2.str, "n expression" ); $$ = nullptr; } 693 | IDENTIFIER type_qualifier // invalid syntax rule s693 | IDENTIFIER type_qualifier // invalid syntax rule 694 694 { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; } 695 | IDENTIFIER storage_class // invalid syntax rule s695 | IDENTIFIER storage_class // invalid syntax rule 696 696 { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; } 697 | IDENTIFIER basic_type_name // invalid syntax rule s697 | IDENTIFIER basic_type_name // invalid syntax rule 698 698 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 699 | IDENTIFIER TYPEDEFname // invalid syntax rule s699 | IDENTIFIER TYPEDEFname // invalid syntax rule 700 700 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 701 | IDENTIFIER TYPEGENname // invalid syntax rule s701 | IDENTIFIER TYPEGENname // invalid syntax rule 702 702 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 703 703 ; … … 1275 1275 | DEFAULT ':' { $$ = new ClauseNode( build_default( yylloc ) ); } 1276 1276 // A semantic check is required to ensure only one default clause per switch/choose statement. 1277 | DEFAULT error // invalid syntax rule s1277 | DEFAULT error // invalid syntax rule 1278 1278 { SemanticError( yylloc, "syntax error, colon missing after default." ); $$ = nullptr; } 1279 1279 ; … … 1405 1405 else { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; } 1406 1406 } 1407 | comma_expression updowneq comma_expression '~' '@' // CFA, invalid syntax rule s1407 | comma_expression updowneq comma_expression '~' '@' // CFA, invalid syntax rule 1408 1408 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1409 | '@' updowneq '@' // CFA, invalid syntax rule s1409 | '@' updowneq '@' // CFA, invalid syntax rule 1410 1410 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1411 | '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rule s1411 | '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rule 1412 1412 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1413 | comma_expression updowneq '@' '~' '@' // CFA, invalid syntax rule s1413 | comma_expression updowneq '@' '~' '@' // CFA, invalid syntax rule 1414 1414 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1415 | '@' updowneq '@' '~' '@' // CFA, invalid syntax rule s1415 | '@' updowneq '@' '~' '@' // CFA, invalid syntax rule 1416 1416 { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; } 1417 1417 … … 1434 1434 else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE ); 1435 1435 } 1436 | comma_expression ';' '@' updowneq '@' // CFA, invalid syntax rule s1436 | comma_expression ';' '@' updowneq '@' // CFA, invalid syntax rule 1437 1437 { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; } 1438 1438 1439 1439 | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA 1440 1440 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); } 1441 | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, invalid syntax rule s1441 | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, invalid syntax rule 1442 1442 { 1443 1443 if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; } … … 1452 1452 | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA 1453 1453 { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); } 1454 | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rule s1454 | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rule 1455 1455 { 1456 1456 if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; } … … 1511 1511 else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr ); 1512 1512 } 1513 | declaration '@' updowneq '@' '~' '@' // CFA, invalid syntax rule s1513 | declaration '@' updowneq '@' '~' '@' // CFA, invalid syntax rule 1514 1514 { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; } 1515 1515 … … 1666 1666 { $$ = build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); } 1667 1667 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1668 | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rule s1668 | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rule 1669 1669 { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1670 1670 | wor_waitfor_clause wor when_clause_opt timeout statement wor when_clause ELSE statement … … 1708 1708 | wor_waituntil_clause wor when_clause_opt ELSE statement 1709 1709 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_else( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); } 1710 | wor_waituntil_clause wor when_clause_opt timeout statement %prec THEN1711 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }1712 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)1713 | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules1714 { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }1715 | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement1716 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1,1717 new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR,1718 build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ),1719 build_waituntil_else( yylloc, $7, maybe_build_compound( yylloc, $9 ) ) ) ); }1720 1710 ; 1721 1711 1722 1712 waituntil_statement: 1723 1713 wor_waituntil_clause %prec THEN 1724 // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement. 1725 { 1726 $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) ); 1727 // $$ = new StatementNode( build_compound( yylloc, nullptr ) ); 1728 } 1714 { $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) ); } 1729 1715 ; 1730 1716 … … 1868 1854 1869 1855 KR_parameter_list: 1870 push c_declaration pop';'1871 { $$ = $ 2; }1872 | KR_parameter_list push c_declaration pop';'1873 { $$ = $1->appendList( $ 3); }1856 c_declaration ';' 1857 { $$ = $1; } 1858 | KR_parameter_list c_declaration ';' 1859 { $$ = $1->appendList( $2 ); } 1874 1860 ; 1875 1861 … … 2007 1993 TYPEDEF cfa_variable_specifier 2008 1994 { 2009 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, " 1" );1995 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "cfa_typedef_declaration 1" ); 2010 1996 $$ = $2->addTypedef(); 2011 1997 } 2012 1998 | TYPEDEF cfa_function_specifier 2013 1999 { 2014 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, " 2" );2000 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "cfa_typedef_declaration 2" ); 2015 2001 $$ = $2->addTypedef(); 2016 2002 } 2017 2003 | cfa_typedef_declaration pop ',' push identifier 2018 2004 { 2019 typedefTable.addToEnclosingScope( *$5, TYPEDEFname, " 3" );2005 typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "cfa_typedef_declaration 3" ); 2020 2006 $$ = $1->appendList( $1->cloneType( $5 ) ); 2021 2007 } … … 2028 2014 TYPEDEF type_specifier declarator 2029 2015 { 2030 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, " 4" );2016 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 1" ); 2031 2017 if ( $2->type->forall || ($2->type->kind == TypeData::Aggregate && $2->type->aggregate.params) ) { 2032 2018 SemanticError( yylloc, "forall qualifier in typedef is currently unimplemented." ); $$ = nullptr; 2033 2019 } else $$ = $3->addType( $2 )->addTypedef(); // watchout frees $2 and $3 2034 2020 } 2035 | typedef_declaration pop ',' pushdeclarator2036 { 2037 typedefTable.addToEnclosingScope( *$ 5->name, TYPEDEFname, "5" );2038 $$ = $1->appendList( $1->cloneBaseType( $ 5)->addTypedef() );2021 | typedef_declaration ',' declarator 2022 { 2023 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 2" ); 2024 $$ = $1->appendList( $1->cloneBaseType( $3 )->addTypedef() ); 2039 2025 } 2040 2026 | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 ) … … 2052 2038 SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr; 2053 2039 } 2054 | typedef_expression pop ',' pushidentifier '=' assignment_expression2040 | typedef_expression ',' identifier '=' assignment_expression 2055 2041 { 2056 2042 SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr; … … 2465 2451 | aggregate_key attribute_list_opt identifier 2466 2452 { 2467 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef2453 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type: 1" ); 2468 2454 forall = false; // reset 2469 2455 } … … 2474 2460 | aggregate_key attribute_list_opt TYPEDEFname // unqualified type name 2475 2461 { 2476 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef2462 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type: 2" ); 2477 2463 forall = false; // reset 2478 2464 } … … 2484 2470 | aggregate_key attribute_list_opt TYPEGENname // unqualified type name 2485 2471 { 2486 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef2472 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type: 3" ); 2487 2473 forall = false; // reset 2488 2474 } … … 2505 2491 aggregate_key attribute_list_opt identifier 2506 2492 { 2507 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname );2493 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type_nobody" ); 2508 2494 forall = false; // reset 2509 2495 $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 ); … … 2680 2666 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 2681 2667 { $$ = DeclarationNode::newEnum( nullptr, $4, true, false )->addQualifiers( $2 ); } 2668 | ENUM attribute_list_opt '!' '{' enumerator_list comma_opt '}' // invalid syntax rule 2669 { SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; } 2682 2670 | ENUM attribute_list_opt identifier 2683 { typedefTable.makeTypedef( *$3 ); }2671 { typedefTable.makeTypedef( *$3, "enum_type 1" ); } 2684 2672 hide_opt '{' enumerator_list comma_opt '}' 2685 2673 { $$ = DeclarationNode::newEnum( $3, $7, true, false, nullptr, $5 )->addQualifiers( $2 ); } 2686 | ENUM attribute_list_opt typedef_name // unqualified type name 2687 hide_opt '{' enumerator_list comma_opt '}' 2674 | ENUM attribute_list_opt typedef_name hide_opt '{' enumerator_list comma_opt '}' // unqualified type name 2688 2675 { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); } 2689 2676 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}' … … 2694 2681 $$ = DeclarationNode::newEnum( nullptr, $7, true, true, $3 )->addQualifiers( $5 ); 2695 2682 } 2683 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // unqualified type name 2684 { SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; } 2685 | ENUM '(' ')' attribute_list_opt '{' enumerator_list comma_opt '}' 2686 { 2687 $$ = DeclarationNode::newEnum( nullptr, $6, true, true )->addQualifiers( $4 ); 2688 } 2689 | ENUM '(' ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // invalid syntax rule 2690 { SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; } 2696 2691 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2697 2692 { … … 2699 2694 SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); 2700 2695 } 2701 typedefTable.makeTypedef( *$6 );2696 typedefTable.makeTypedef( *$6, "enum_type 2" ); 2702 2697 } 2703 2698 hide_opt '{' enumerator_list comma_opt '}' … … 2705 2700 $$ = DeclarationNode::newEnum( $6, $11, true, true, $3, $9 )->addQualifiers( $5 )->addQualifiers( $7 ); 2706 2701 } 2707 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt 2708 hide_opt '{' enumerator_list comma_opt '}' 2702 | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt hide_opt '{' enumerator_list comma_opt '}' 2703 { 2704 $$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 ); 2705 } 2706 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}' 2709 2707 { 2710 2708 $$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3, $8 )->addQualifiers( $5 )->addQualifiers( $7 ); 2709 } 2710 | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}' 2711 { 2712 $$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 ); 2711 2713 } 2712 2714 | enum_type_nobody … … 2722 2724 enum_type_nobody: // enum - {...} 2723 2725 ENUM attribute_list_opt identifier 2724 { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, nullptr, false, false )->addQualifiers( $2 ); } 2726 { 2727 typedefTable.makeTypedef( *$3, "enum_type_nobody 1" ); 2728 $$ = DeclarationNode::newEnum( $3, nullptr, false, false )->addQualifiers( $2 ); 2729 } 2725 2730 | ENUM attribute_list_opt type_name 2726 { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, nullptr, false, false )->addQualifiers( $2 ); } 2731 { 2732 typedefTable.makeTypedef( *$3->type->symbolic.name, "enum_type_nobody 2" ); 2733 $$ = DeclarationNode::newEnum( $3->type->symbolic.name, nullptr, false, false )->addQualifiers( $2 ); 2734 } 2727 2735 ; 2728 2736 … … 2792 2800 { $$ = nullptr; } 2793 2801 | parameter_list 2794 | parameter_list pop ',' pushELLIPSIS2802 | parameter_list ',' ELLIPSIS 2795 2803 { $$ = $1->addVarArgs(); } 2796 2804 ; … … 2799 2807 abstract_parameter_declaration 2800 2808 | parameter_declaration 2801 | parameter_list pop ',' pushabstract_parameter_declaration2802 { $$ = $1->appendList( $ 5); }2803 | parameter_list pop ',' pushparameter_declaration2804 { $$ = $1->appendList( $ 5); }2809 | parameter_list ',' abstract_parameter_declaration 2810 { $$ = $1->appendList( $3 ); } 2811 | parameter_list ',' parameter_declaration 2812 { $$ = $1->appendList( $3 ); } 2805 2813 ; 2806 2814 … … 2969 2977 type_class identifier_or_type_name 2970 2978 { 2971 typedefTable.addToScope( *$2, TYPEDEFname, " 9" );2979 typedefTable.addToScope( *$2, TYPEDEFname, "type_parameter 1" ); 2972 2980 if ( $1 == ast::TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated, use T " ); } 2973 2981 if ( $1 == ast::TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated, use T &" ); } … … 2977 2985 { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); } 2978 2986 | identifier_or_type_name new_type_class 2979 { typedefTable.addToScope( *$1, TYPEDEFname, " 9" ); }2987 { typedefTable.addToScope( *$1, TYPEDEFname, "type_parameter 2" ); } 2980 2988 type_initializer_opt assertion_list_opt 2981 2989 { $$ = DeclarationNode::newTypeParam( $2, $1 )->addTypeInitializer( $4 )->addAssertions( $5 ); } 2982 2990 | '[' identifier_or_type_name ']' 2983 2991 { 2984 typedefTable.addToScope( *$2, TYPEDIMname, " 9" );2992 typedefTable.addToScope( *$2, TYPEDIMname, "type_parameter 3" ); 2985 2993 $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dimension, $2 ); 2986 2994 } … … 3064 3072 identifier_or_type_name 3065 3073 { 3066 typedefTable.addToEnclosingScope( *$1, TYPEDEFname, " 10" );3074 typedefTable.addToEnclosingScope( *$1, TYPEDEFname, "type_declarator_name 1" ); 3067 3075 $$ = DeclarationNode::newTypeDecl( $1, nullptr ); 3068 3076 } 3069 3077 | identifier_or_type_name '(' type_parameter_list ')' 3070 3078 { 3071 typedefTable.addToEnclosingScope( *$1, TYPEGENname, " 11" );3079 typedefTable.addToEnclosingScope( *$1, TYPEGENname, "type_declarator_name 2" ); 3072 3080 $$ = DeclarationNode::newTypeDecl( $1, $3 ); 3073 3081 } … … 3163 3171 | IDENTIFIER IDENTIFIER 3164 3172 { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; } 3165 | IDENTIFIER type_qualifier // invalid syntax rule s3173 | IDENTIFIER type_qualifier // invalid syntax rule 3166 3174 { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; } 3167 | IDENTIFIER storage_class // invalid syntax rule s3175 | IDENTIFIER storage_class // invalid syntax rule 3168 3176 { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; } 3169 | IDENTIFIER basic_type_name // invalid syntax rule s3177 | IDENTIFIER basic_type_name // invalid syntax rule 3170 3178 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 3171 | IDENTIFIER TYPEDEFname // invalid syntax rule s3179 | IDENTIFIER TYPEDEFname // invalid syntax rule 3172 3180 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 3173 | IDENTIFIER TYPEGENname // invalid syntax rule s3181 | IDENTIFIER TYPEGENname // invalid syntax rule 3174 3182 { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; } 3175 3183 | external_function_definition … … 3458 3466 3459 3467 variable_function: 3460 '(' variable_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3461 { $$ = $2->addParamList( $ 6); }3462 | '(' attribute_list variable_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3463 { $$ = $3->addQualifiers( $2 )->addParamList( $ 7); }3468 '(' variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3469 { $$ = $2->addParamList( $5 ); } 3470 | '(' attribute_list variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3471 { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); } 3464 3472 | '(' variable_function ')' // redundant parenthesis 3465 3473 { $$ = $2; } … … 3481 3489 3482 3490 function_no_ptr: 3483 paren_identifier '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3484 { $$ = $1->addParamList( $ 4); }3485 | '(' function_ptr ')' '(' p ush parameter_type_list_opt pop')'3486 { $$ = $2->addParamList( $ 6); }3487 | '(' attribute_list function_ptr ')' '(' p ush parameter_type_list_opt pop')'3488 { $$ = $3->addQualifiers( $2 )->addParamList( $ 7); }3491 paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3492 { $$ = $1->addParamList( $3 ); } 3493 | '(' function_ptr ')' '(' parameter_type_list_opt ')' 3494 { $$ = $2->addParamList( $5 ); } 3495 | '(' attribute_list function_ptr ')' '(' parameter_type_list_opt ')' 3496 { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); } 3489 3497 | '(' function_no_ptr ')' // redundant parenthesis 3490 3498 { $$ = $2; } … … 3535 3543 paren_identifier '(' identifier_list ')' // function_declarator handles empty parameter 3536 3544 { $$ = $1->addIdList( $3 ); } 3537 | '(' KR_function_ptr ')' '(' p ush parameter_type_list_opt pop')'3538 { $$ = $2->addParamList( $ 6); }3539 | '(' attribute_list KR_function_ptr ')' '(' p ush parameter_type_list_opt pop')'3540 { $$ = $3->addQualifiers( $2 )->addParamList( $ 7); }3545 | '(' KR_function_ptr ')' '(' parameter_type_list_opt ')' 3546 { $$ = $2->addParamList( $5 ); } 3547 | '(' attribute_list KR_function_ptr ')' '(' parameter_type_list_opt ')' 3548 { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); } 3541 3549 | '(' KR_function_no_ptr ')' // redundant parenthesis 3542 3550 { $$ = $2; } … … 3582 3590 { 3583 3591 // hide type name in enclosing scope by variable name 3584 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, " ID" );3592 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "paren_type" ); 3585 3593 } 3586 3594 | '(' paren_type ')' … … 3627 3635 3628 3636 variable_type_function: 3629 '(' variable_type_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3630 { $$ = $2->addParamList( $ 6); }3631 | '(' attribute_list variable_type_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3632 { $$ = $3->addQualifiers( $2 )->addParamList( $ 7); }3637 '(' variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3638 { $$ = $2->addParamList( $5 ); } 3639 | '(' attribute_list variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3640 { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); } 3633 3641 | '(' variable_type_function ')' // redundant parenthesis 3634 3642 { $$ = $2; } … … 3650 3658 3651 3659 function_type_no_ptr: 3652 paren_type '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3653 { $$ = $1->addParamList( $ 4); }3654 | '(' function_type_ptr ')' '(' p ush parameter_type_list_opt pop')'3655 { $$ = $2->addParamList( $ 6); }3656 | '(' attribute_list function_type_ptr ')' '(' p ush parameter_type_list_opt pop')'3657 { $$ = $3->addQualifiers( $2 )->addParamList( $ 7); }3660 paren_type '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3661 { $$ = $1->addParamList( $3 ); } 3662 | '(' function_type_ptr ')' '(' parameter_type_list_opt ')' 3663 { $$ = $2->addParamList( $5 ); } 3664 | '(' attribute_list function_type_ptr ')' '(' parameter_type_list_opt ')' 3665 { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); } 3658 3666 | '(' function_type_no_ptr ')' // redundant parenthesis 3659 3667 { $$ = $2; } … … 3726 3734 3727 3735 identifier_parameter_function: 3728 paren_identifier '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3729 { $$ = $1->addParamList( $ 4); }3730 | '(' identifier_parameter_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3731 { $$ = $2->addParamList( $ 6); }3736 paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3737 { $$ = $1->addParamList( $3 ); } 3738 | '(' identifier_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3739 { $$ = $2->addParamList( $5 ); } 3732 3740 | '(' identifier_parameter_function ')' // redundant parenthesis 3733 3741 { $$ = $2; } … … 3779 3787 3780 3788 type_parameter_function: 3781 typedef_name '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3782 { $$ = $1->addParamList( $ 4); }3783 | '(' type_parameter_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3784 { $$ = $2->addParamList( $ 6); }3789 typedef_name '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3790 { $$ = $1->addParamList( $3 ); } 3791 | '(' type_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3792 { $$ = $2->addParamList( $5 ); } 3785 3793 ; 3786 3794 … … 3829 3837 3830 3838 abstract_function: 3831 '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3832 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $ 3, nullptr ); }3833 | '(' abstract_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3834 { $$ = $2->addParamList( $ 6); }3839 '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3840 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); } 3841 | '(' abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3842 { $$ = $2->addParamList( $5 ); } 3835 3843 | '(' abstract_function ')' // redundant parenthesis 3836 3844 { $$ = $2; } … … 3952 3960 3953 3961 abstract_parameter_function: 3954 '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3955 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $ 3, nullptr ); }3956 | '(' abstract_parameter_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)3957 { $$ = $2->addParamList( $ 6); }3962 '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3963 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); } 3964 | '(' abstract_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 3965 { $$ = $2->addParamList( $5 ); } 3958 3966 | '(' abstract_parameter_function ')' // redundant parenthesis 3959 3967 { $$ = $2; } … … 3992 4000 // This pattern parses a declaration of an abstract variable, but does not allow "int ()" for a function pointer. 3993 4001 // 3994 // 3995 // 3996 // 3997 // 3998 // 3999 // 4002 // struct S { 4003 // int; 4004 // int *; 4005 // int [10]; 4006 // int (*)(); 4007 // }; 4000 4008 4001 4009 variable_abstract_declarator: … … 4031 4039 4032 4040 variable_abstract_function: 4033 '(' variable_abstract_ptr ')' '(' p ush parameter_type_list_opt pop')' // empty parameter list OBSOLESCENT (see 3)4034 { $$ = $2->addParamList( $ 6); }4041 '(' variable_abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3) 4042 { $$ = $2->addParamList( $5 ); } 4035 4043 | '(' variable_abstract_function ')' // redundant parenthesis 4036 4044 { $$ = $2; } -
src/ResolvExpr/CommonType.cc
r92355883 r2a301ff 696 696 void postvisit( const ast::BasicType * basic ) { 697 697 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) { 698 #warning remove casts when `commonTypes` moved to new AST699 700 /*701 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];702 if (703 ( ( kind == basic->kind && basic->qualifiers >= basic2->qualifiers )704 || widen.first )705 && ( ( kind == basic2->kind && basic->qualifiers <= basic2->qualifiers )706 || widen.second )707 ) {708 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };709 }710 */711 698 ast::BasicType::Kind kind; 712 699 if (basic->kind != basic2->kind && !widen.first && !widen.second) return; … … 719 706 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers }; 720 707 } 721 722 708 } else if ( 723 709 dynamic_cast< const ast::ZeroType * >( type2 ) 724 710 || dynamic_cast< const ast::OneType * >( type2 ) 725 711 ) { 726 #warning remove casts when `commonTypes` moved to new AST727 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];728 /*729 if ( // xxx - what does qualifier even do here??730 ( ( basic->qualifiers >= type2->qualifiers )731 || widen.first )732 && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers )733 || widen.second )734 )735 */736 712 if (widen.second) { 737 713 result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers }; 738 714 } 739 715 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { 740 #warning remove casts when `commonTypes` moved to new AST741 716 const ast::EnumDecl* enumDecl = enumInst->base; 742 717 if ( enumDecl->base ) { 743 718 result = enumDecl->base.get(); 744 719 } else { 720 #warning remove casts when `commonTypes` moved to new AST 745 721 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ]; 746 722 if ( … … 763 739 auto entry = open.find( *var ); 764 740 if ( entry != open.end() ) { 765 // if (tenv.lookup(*var)) {766 741 ast::AssertionSet need, have; 767 742 if ( ! tenv.bindVar( -
src/ResolvExpr/ResolveTypeof.h
r92355883 r2a301ff 30 30 Type *resolveTypeof( Type*, const SymTab::Indexer &indexer ); 31 31 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & ); 32 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & ); 32 33 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & ); 33 34 const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext &); -
src/ResolvExpr/Unify.cc
r92355883 r2a301ff 32 32 #include "AST/Type.hpp" 33 33 #include "AST/TypeEnvironment.hpp" 34 #include "Common/Eval.h" // for eval 34 35 #include "Common/PassVisitor.h" // for PassVisitor 35 36 #include "CommonType.hpp" // for commonType … … 779 780 } 780 781 782 // Unification of Expressions 783 // 784 // Boolean outcome (obvious): Are they basically spelled the same? 785 // Side effect of binding variables (subtle): if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T` 786 // 787 // Context: if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2` 788 // where the VAREXPR are meant as notational metavariables representing the fact that unification always 789 // sees distinct ast::VariableExpr objects at these positions 790 791 static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env, 792 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, 793 WidenMode widen ); 794 795 class UnifyExpr final : public ast::WithShortCircuiting { 796 const ast::Expr * e2; 797 ast::TypeEnvironment & tenv; 798 ast::AssertionSet & need; 799 ast::AssertionSet & have; 800 const ast::OpenVarSet & open; 801 WidenMode widen; 802 public: 803 bool result; 804 805 private: 806 807 void tryMatchOnStaticValue( const ast::Expr * e1 ) { 808 Evaluation r1 = eval(e1); 809 Evaluation r2 = eval(e2); 810 811 if ( ! r1.hasKnownValue ) return; 812 if ( ! r2.hasKnownValue ) return; 813 814 if (r1.knownValue != r2.knownValue) return; 815 816 visit_children = false; 817 result = true; 818 } 819 820 public: 821 822 void previsit( const ast::Node * ) { assert(false); } 823 824 void previsit( const ast::Expr * e1 ) { 825 tryMatchOnStaticValue( e1 ); 826 visit_children = false; 827 } 828 829 void previsit( const ast::CastExpr * e1 ) { 830 tryMatchOnStaticValue( e1 ); 831 832 if (result) { 833 assert (visit_children == false); 834 } else { 835 assert (visit_children == true); 836 visit_children = false; 837 838 auto e2c = dynamic_cast< const ast::CastExpr * >( e2 ); 839 if ( ! e2c ) return; 840 841 // inspect casts' target types 842 if ( ! unifyExact( 843 e1->result, e2c->result, tenv, need, have, open, widen ) ) return; 844 845 // inspect casts' inner expressions 846 result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen ); 847 } 848 } 849 850 void previsit( const ast::VariableExpr * e1 ) { 851 tryMatchOnStaticValue( e1 ); 852 853 if (result) { 854 assert (visit_children == false); 855 } else { 856 assert (visit_children == true); 857 visit_children = false; 858 859 auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 ); 860 if ( ! e2v ) return; 861 862 assert(e1->var); 863 assert(e2v->var); 864 865 // conservative: variable exprs match if their declarations are represented by the same C++ AST object 866 result = (e1->var == e2v->var); 867 } 868 } 869 870 void previsit( const ast::SizeofExpr * e1 ) { 871 tryMatchOnStaticValue( e1 ); 872 873 if (result) { 874 assert (visit_children == false); 875 } else { 876 assert (visit_children == true); 877 visit_children = false; 878 879 auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 ); 880 if ( ! e2so ) return; 881 882 assert((e1->type != nullptr) ^ (e1->expr != nullptr)); 883 assert((e2so->type != nullptr) ^ (e2so->expr != nullptr)); 884 if ( ! (e1->type && e2so->type) ) return; 885 886 // expression unification calls type unification (mutual recursion) 887 result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen ); 888 } 889 } 890 891 UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need, 892 ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen ) 893 : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {} 894 }; 895 896 static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env, 897 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, 898 WidenMode widen ) { 899 assert( e1 && e2 ); 900 return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen ); 901 } 902 781 903 class Unify_new final : public ast::WithShortCircuiting { 782 904 const ast::Type * type2; … … 820 942 if ( ! array2 ) return; 821 943 822 // to unify, array types must both be VLA or both not VLA and both must have a823 // dimension expression or not have a dimension824 944 if ( array->isVarLen != array2->isVarLen ) return; 825 if ( ! array->isVarLen && ! array2->isVarLen 826 && array->dimension && array2->dimension ) { 827 auto ce1 = array->dimension.as< ast::ConstantExpr >(); 828 auto ce2 = array2->dimension.as< ast::ConstantExpr >(); 829 830 // see C11 Reference Manual 6.7.6.2.6 831 // two array types with size specifiers that are integer constant expressions are 832 // compatible if both size specifiers have the same constant value 833 if ( ce1 && ce2 && ce1->intValue() != ce2->intValue() ) return; 945 if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return; 946 947 if ( array->dimension ) { 948 assert( array2->dimension ); 949 // type unification calls expression unification (mutual recursion) 950 if ( ! unify(array->dimension, array2->dimension, 951 tenv, need, have, open, widen) ) return; 834 952 } 835 953 … … 1180 1298 auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 ); 1181 1299 auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 ); 1182 ast::OpenVarSet::const_iterator1183 entry1 = var1 ? open.find( *var1 ) : open.end(),1184 entry2 = var2 ? open.find( *var2 ) : open.end();1185 // bool isopen1 = entry1 != open.end();1186 // bool isopen2 = entry2 != open.end();1187 1300 bool isopen1 = var1 && env.lookup(*var1); 1188 1301 bool isopen2 = var2 && env.lookup(*var2); 1189 1302 1190 /*1191 if ( isopen1 && isopen2 ) {1192 if ( entry1->second.kind != entry2->second.kind ) return false;1193 return env.bindVarToVar(1194 var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,1195 open, widen );1196 } else if ( isopen1 ) {1197 return env.bindVar( var1, type2, entry1->second, need, have, open, widen );1198 } else if ( isopen2 ) {1199 return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );1200 } */1201 1303 if ( isopen1 && isopen2 ) { 1202 1304 if ( var1->base->kind != var2->base->kind ) return false; … … 1208 1310 } else if ( isopen2 ) { 1209 1311 return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen ); 1210 } else {1312 } else { 1211 1313 return ast::Pass<Unify_new>::read( 1212 1314 type1, type2, env, need, have, open, widen ); 1213 1315 } 1214 1215 1316 } 1216 1317 -
src/SymTab/FixFunction.cc
r92355883 r2a301ff 109 109 110 110 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) { 111 return new ast::ObjectDecl{ 112 func->location, func->name, new ast::PointerType{ func->type }, nullptr, 111 // Cannot handle cases with asserions. 112 assert( func->assertions.empty() ); 113 return new ast::ObjectDecl{ 114 func->location, func->name, new ast::PointerType( func->type ), nullptr, 113 115 func->storage, func->linkage, nullptr, copy( func->attributes ) }; 114 116 } … … 117 119 118 120 const ast::Type * postvisit( const ast::ArrayType * array ) { 119 return new ast::PointerType{ 120 array->base, array->dimension, array->isVarLen, array->isStatic, 121 return new ast::PointerType{ 122 array->base, array->dimension, array->isVarLen, array->isStatic, 121 123 array->qualifiers }; 122 124 } -
src/SymTab/GenImplicitCall.cpp
r92355883 r2a301ff 16 16 #include "GenImplicitCall.hpp" 17 17 18 #include "AST/Copy.hpp" // for deepCopy 18 19 #include "AST/Decl.hpp" // for ObjectDecl 19 20 #include "AST/Expr.hpp" // for ConstantExpr, UntypedExpr,... … … 115 116 std::string cmp, update; 116 117 118 const ast::Expr * dimension = deepCopy( array->dimension ); 117 119 if ( forward ) { 118 120 // generate: for ( int i = 0; i < N; ++i ) 119 121 begin = ast::ConstantExpr::from_int( loc, 0 ); 120 end = array->dimension;122 end = dimension; 121 123 cmp = "?<?"; 122 124 update = "++?"; … … 124 126 // generate: for ( int i = N-1; i >= 0; --i ) 125 127 begin = ast::UntypedExpr::createCall( loc, "?-?", 126 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );128 { dimension, ast::ConstantExpr::from_int( loc, 1 ) } ); 127 129 end = ast::ConstantExpr::from_int( loc, 0 ); 128 130 cmp = "?>=?"; -
src/Validate/Autogen.cpp
r92355883 r2a301ff 532 532 ) 533 533 ); 534 returngenImplicitCall(534 auto stmt = genImplicitCall( 535 535 srcParam, dstSelect, location, func->name, 536 536 field, direction 537 537 ); 538 // This could return the above directly, except the generated code is 539 // built using the structure's members and that means all the scoped 540 // names (the forall parameters) are incorrect. This corrects them. 541 if ( stmt && !decl->params.empty() ) { 542 ast::DeclReplacer::TypeMap oldToNew; 543 for ( auto pair : group_iterate( decl->params, func->type_params ) ) { 544 oldToNew.emplace( std::get<0>(pair), std::get<1>(pair) ); 545 } 546 auto node = ast::DeclReplacer::replace( stmt, oldToNew ); 547 stmt = strict_dynamic_cast<const ast::Stmt *>( node ); 548 } 549 return stmt; 538 550 } 539 551 -
src/Validate/FixQualifiedTypes.cpp
r92355883 r2a301ff 89 89 } 90 90 91 ast::Expr const * postvisit( ast::QualifiedNameExpr const * t ) {91 ast::Expr const * postvisit( ast::QualifiedNameExpr const * t ) { 92 92 assert( location ); 93 if ( t->type_decl ) { 94 auto enumName = t->type_decl->name; 95 const ast::EnumDecl * enumDecl = symtab.lookupEnum( enumName ); 96 for ( ast::ptr<ast::Decl> const & member : enumDecl->members ) { 97 if ( auto memberAsObj = member.as<ast::ObjectDecl>() ) { 98 if ( memberAsObj->name == t->name ) { 99 return new ast::VariableExpr( t->location, memberAsObj ); 100 } 101 } else { 102 assertf( false, "unhandled qualified child type"); 93 if ( !t->type_decl ) return t; 94 95 auto enumName = t->type_decl->name; 96 const ast::EnumDecl * enumDecl = symtab.lookupEnum( enumName ); 97 for ( ast::ptr<ast::Decl> const & member : enumDecl->members ) { 98 if ( auto memberAsObj = member.as<ast::ObjectDecl>() ) { 99 if ( memberAsObj->name == t->name ) { 100 return new ast::VariableExpr( t->location, memberAsObj ); 103 101 } 102 } else { 103 assertf( false, "unhandled qualified child type" ); 104 104 } 105 } 105 106 106 auto var = new ast::ObjectDecl( t->location, t->name, 107 new ast::EnumInstType(enumDecl, ast::CV::Const), nullptr, {}, ast::Linkage::Cforall ); 108 var->mangleName = Mangle::mangle( var ); 109 return new ast::VariableExpr( t->location, var ); 110 } 111 112 return t; 107 auto var = new ast::ObjectDecl( t->location, t->name, 108 new ast::EnumInstType( enumDecl, ast::CV::Const ), 109 nullptr, {}, ast::Linkage::Cforall ); 110 var->mangleName = Mangle::mangle( var ); 111 return new ast::VariableExpr( t->location, var ); 113 112 } 114 113 -
src/Validate/ForallPointerDecay.cpp
r92355883 r2a301ff 23 23 #include "Common/CodeLocation.h" 24 24 #include "Common/ToString.hpp" 25 #include "Common/utility.h" 25 26 #include "SymTab/FixFunction.h" 26 27 #include "AST/Print.hpp"28 27 29 28 namespace Validate { … … 51 50 } 52 51 53 template<typename T> 54 void append( std::vector<T> & dst, std::vector<T> & src ) { 55 dst.reserve( dst.size() + src.size() ); 56 for ( auto el : src ) { 57 dst.emplace_back( std::move( el ) ); 58 } 59 src.clear(); 52 ast::FunctionDecl * updateAssertions( ast::FunctionDecl * decl ) { 53 auto type = ast::mutate( decl->type.get() ); 54 type->assertions.clear(); 55 type->assertions.reserve( decl->assertions.size() ); 56 for ( auto & assertion : decl->assertions ) { 57 type->assertions.emplace_back( 58 new ast::VariableExpr( decl->location, assertion ) ); 59 } 60 decl->type = type; 61 return decl; 60 62 } 61 63 … … 96 98 decl->get_type() ) ) { 97 99 auto moreAsserts = expandTrait( traitInst ); 98 append( assertions, moreAsserts );100 splice( assertions, moreAsserts ); 99 101 } else { 100 102 assertions.push_back( decl ); … … 108 110 static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) { 109 111 TypeDeclVec typeDecls; 112 typeDecls.reserve( old.size() ); 110 113 for ( const ast::TypeDecl * typeDecl : old ) { 111 114 typeDecls.push_back( ast::mutate_field( typeDecl, … … 123 126 mut->assertions = expandAssertions( decl->assertions ); 124 127 // Update the assertion list on the type as well. 125 auto mutType = ast::mutate( mut->type.get() ); 126 mutType->assertions.clear(); 127 for ( auto & assertion : mut->assertions ) { 128 mutType->assertions.emplace_back( 129 new ast::VariableExpr( mut->location, assertion ) ); 130 } 131 mut->type = mutType; 132 return mut; 128 return updateAssertions( mut ); 133 129 } 134 130 … … 154 150 const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) { 155 151 std::vector<ast::ptr<ast::DeclWithType>> ret; 152 ret.reserve( assertions.size() ); 156 153 for ( const auto & assn : assertions ) { 157 154 bool isVoid = false; … … 187 184 } 188 185 186 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) { 187 if ( decl->assertions.empty() ) { 188 return decl; 189 } 190 return updateAssertions( mutate( decl ) ); 191 } 192 189 193 const ast::StructDecl * previsit( const ast::StructDecl * decl ) { 190 194 if ( decl->params.empty() ) { … … 204 208 }; 205 209 206 struct O beratorChecker final {210 struct OperatorChecker final { 207 211 void previsit( const ast::ObjectDecl * obj ) { 208 if ( CodeGen::isOperator( obj->name ) ) { 209 auto type = obj->type->stripDeclarator(); 210 if ( ! dynamic_cast< const ast::FunctionType * >( type ) ) { 211 SemanticError( obj->location, 212 toCString( "operator ", obj->name.c_str(), " is not " 213 "a function or function pointer." ) ); 214 } 215 } 212 if ( !CodeGen::isOperator( obj->name ) ) return; 213 auto type = obj->type->stripDeclarator(); 214 if ( dynamic_cast< const ast::FunctionType * >( type ) ) return; 215 SemanticError( obj->location, 216 toCString( "operator ", obj->name.c_str(), 217 " is not a function or function pointer." ) ); 216 218 } 217 219 }; … … 234 236 ast::Pass<TraitExpander>::run( transUnit ); 235 237 ast::Pass<AssertionFunctionFixer>::run( transUnit ); 236 ast::Pass<OberatorChecker>::run( transUnit ); 238 ast::Pass<OperatorChecker>::run( transUnit ); 239 } 240 241 void fixUniqueIds( ast::TranslationUnit & transUnit ) { 237 242 ast::Pass<UniqueFixCore>::run( transUnit ); 238 243 } -
src/Validate/ForallPointerDecay.hpp
r92355883 r2a301ff 27 27 28 28 /// Cleans up assertion lists and expands traits. 29 /// Also checks that operator names are used properly on functions and 30 /// assigns unique IDs. This is a "legacy" pass. 29 /// Also checks that operator names are used properly on functions. 30 /// This is a "legacy" pass. 31 /// Must happen before auto-gen routines are added. 32 void decayForallPointers( ast::TranslationUnit & transUnit ); 33 34 /// Sets uniqueIds on any declarations that do not have one set. 31 35 /// Must be after implement concurrent keywords; because uniqueIds must be 32 36 /// set on declaration before resolution. 33 /// Must happen before auto-gen routines are added. 34 void decayForallPointers( ast::TranslationUnit & transUnit ); 37 void fixUniqueIds( ast::TranslationUnit & transUnit ); 35 38 36 39 /// Expand all traits in an assertion list. -
src/Validate/GenericParameter.cpp
r92355883 r2a301ff 16 16 #include "GenericParameter.hpp" 17 17 18 #include "AST/Copy.hpp"19 18 #include "AST/Decl.hpp" 20 19 #include "AST/Expr.hpp" … … 165 164 166 165 struct TranslateDimensionCore : 167 public WithNoIdSymbolTable, public ast::WithGuards { 166 public WithNoIdSymbolTable, public ast::WithGuards, 167 public ast::WithVisitorRef<TranslateDimensionCore> { 168 168 169 169 // SUIT: Struct- or Union- InstType … … 190 190 191 191 const ast::TypeDecl * postvisit( const ast::TypeDecl * decl ); 192 const ast::Type * postvisit( const ast::FunctionType * type ); 193 const ast::Type * postvisit( const ast::TypeInstType * type ); 194 192 195 const ast::Expr * postvisit( const ast::DimensionExpr * expr ); 193 196 const ast::Expr * postvisit( const ast::Expr * expr ); … … 195 198 }; 196 199 200 // Declaration of type variable: forall( [N] ) -> forall( N & | sized( N ) ) 197 201 const ast::TypeDecl * TranslateDimensionCore::postvisit( 198 202 const ast::TypeDecl * decl ) { … … 206 210 } 207 211 return decl; 212 } 213 214 // Makes postvisit( TypeInstType ) get called on the entries of the function declaration's type's forall list. 215 // Pass.impl.hpp's visit( FunctionType ) does not consider the forall entries to be child nodes. 216 // Workaround is: during the current TranslateDimension pass, manually visit down there. 217 const ast::Type * TranslateDimensionCore::postvisit( 218 const ast::FunctionType * type ) { 219 visitor->maybe_accept( type, &ast::FunctionType::forall ); 220 return type; 221 } 222 223 // Use of type variable, assuming `forall( [N] )` in scope: void (*)( foo( /*dimension*/ N ) & ) -> void (*)( foo( /*dtype*/ N ) & ) 224 const ast::Type * TranslateDimensionCore::postvisit( 225 const ast::TypeInstType * type ) { 226 if ( type->kind == ast::TypeDecl::Dimension ) { 227 auto mutType = ast::mutate( type ); 228 mutType->kind = ast::TypeDecl::Dtype; 229 return mutType; 230 } 231 return type; 208 232 } 209 233 -
src/Validate/LinkReferenceToTypes.cpp
r92355883 r2a301ff 10 10 // Created On : Thr Apr 21 11:41:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Sep 20 16:17:00 202213 // Update Count : 212 // Last Modified On : Fri Jul 14 9:19:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 27 27 struct LinkTypesCore : public WithNoIdSymbolTable, 28 28 public ast::WithCodeLocation, 29 public ast::WithDeclsToAdd<>, 29 30 public ast::WithGuards, 30 31 public ast::WithShortCircuiting, … … 63 64 template<typename AggrDecl> 64 65 AggrDecl const * renameGenericParams( AggrDecl const * decl ); 66 67 // This cluster is used to add declarations (before) but outside of 68 // any "namespaces" which would qualify the names. 69 bool inNamespace = false; 70 std::list<ast::ptr<ast::Decl>> declsToAddOutside; 71 /// The "leaveNamespace" is handled by guard. 72 void enterNamespace(); 73 /// Puts the decl on the back of declsToAddAfter once traversal is 74 /// outside of any namespaces. 75 void addDeclAfterOutside( ast::Decl const * ); 65 76 }; 77 78 void LinkTypesCore::enterNamespace() { 79 if ( inNamespace ) return; 80 inNamespace = true; 81 GuardAction( [this](){ 82 inNamespace = false; 83 declsToAddAfter.splice( declsToAddAfter.begin(), declsToAddOutside ); 84 } ); 85 } 86 87 void LinkTypesCore::addDeclAfterOutside( ast::Decl const * decl ) { 88 if ( inNamespace ) { 89 declsToAddOutside.emplace_back( decl ); 90 } else { 91 declsToAddAfter.emplace_back( decl ); 92 } 93 } 66 94 67 95 ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) { … … 81 109 ast::EnumDecl const * decl = symtab.lookupEnum( type->name ); 82 110 // It's not a semantic error if the enum is not found, just an implicit forward declaration. 83 if ( decl ) { 84 // Just linking in the node. 85 auto mut = ast::mutate( type ); 86 mut->base = decl; 87 type = mut; 88 } 89 if ( !decl || !decl->body ) { 90 auto mut = ast::mutate( type ); 111 // The unset code location is used to detect imaginary declarations. 112 // (They may never be used for enumerations.) 113 if ( !decl || decl->location.isUnset() ) { 114 assert( location ); 115 ast::EnumDecl * mut = new ast::EnumDecl( *location, type->name ); 116 mut->linkage = ast::Linkage::Compiler; 117 decl = mut; 118 symtab.addEnum( decl ); 119 addDeclAfterOutside( decl ); 120 } 121 122 ast::EnumInstType * mut = ast::mutate( type ); 123 124 // Just linking in the node. 125 mut->base = decl; 126 127 if ( !decl->body ) { 91 128 forwardEnums[ mut->name ].push_back( mut ); 92 type = mut; 93 } 94 return type; 129 } 130 return mut; 95 131 } 96 132 … … 98 134 ast::StructDecl const * decl = symtab.lookupStruct( type->name ); 99 135 // It's not a semantic error if the struct is not found, just an implicit forward declaration. 100 if ( decl ) { 101 // Just linking in the node. 102 auto mut = ast::mutate( type ); 103 mut->base = decl; 104 type = mut; 105 } 106 if ( !decl || !decl->body ) { 107 auto mut = ast::mutate( type ); 136 // The unset code location is used to detect imaginary declarations. 137 if ( !decl || decl->location.isUnset() ) { 138 assert( location ); 139 ast::StructDecl * mut = new ast::StructDecl( *location, type->name ); 140 mut->linkage = ast::Linkage::Compiler; 141 decl = mut; 142 symtab.addStruct( decl ); 143 addDeclAfterOutside( decl ); 144 } 145 146 ast::StructInstType * mut = ast::mutate( type ); 147 148 // Just linking in the node. 149 mut->base = decl; 150 151 if ( !decl->body ) { 108 152 forwardStructs[ mut->name ].push_back( mut ); 109 type = mut; 110 } 111 return type; 153 } 154 return mut; 112 155 } 113 156 … … 115 158 ast::UnionDecl const * decl = symtab.lookupUnion( type->name ); 116 159 // It's not a semantic error if the union is not found, just an implicit forward declaration. 117 if ( decl ) { 118 // Just linking in the node. 119 auto mut = ast::mutate( type ); 120 mut->base = decl; 121 type = mut; 122 } 123 if ( !decl || !decl->body ) { 124 auto mut = ast::mutate( type ); 160 // The unset code location is used to detect imaginary declarations. 161 if ( !decl || decl->location.isUnset() ) { 162 assert( location ); 163 ast::UnionDecl * mut = new ast::UnionDecl( *location, type->name ); 164 mut->linkage = ast::Linkage::Compiler; 165 decl = mut; 166 symtab.addUnion( decl ); 167 addDeclAfterOutside( decl ); 168 } 169 170 ast::UnionInstType * mut = ast::mutate( type ); 171 172 // Just linking in the node. 173 mut->base = decl; 174 175 if ( !decl->body ) { 125 176 forwardUnions[ mut->name ].push_back( mut ); 126 type = mut; 127 } 128 return type; 177 } 178 return mut; 129 179 } 130 180 … … 228 278 229 279 ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) { 280 enterNamespace(); 230 281 return renameGenericParams( decl ); 231 282 } … … 246 297 247 298 ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) { 299 enterNamespace(); 248 300 return renameGenericParams( decl ); 249 301 } … … 264 316 265 317 ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) { 266 auto mut = ast::mutate( decl );267 if ( mut->name == "sized" ) {268 // "sized" is a special trait - flick the sized status on for the type variable.269 assertf( mut->params.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", decl->params.size() );270 ast::TypeDecl * td = mut->params.front().get_and_mutate();271 td->sized = true;272 }273 274 318 // There is some overlap with code from decayForallPointers, 275 319 // perhaps reorganization or shared helper functions are called for. 276 320 // Move assertions from type parameters into the body of the trait. 321 auto mut = ast::mutate( decl ); 277 322 for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) { 278 323 auto expanded = expandAssertions( td->assertions ); -
src/Validate/NoIdSymbolTable.hpp
r92355883 r2a301ff 46 46 FORWARD_1( addUnion , const ast::UnionDecl * ) 47 47 FORWARD_1( addTrait , const ast::TraitDecl * ) 48 FORWARD_1( addStruct, const std::string & )49 FORWARD_1( addUnion , const std::string & )50 48 FORWARD_2( addWith , const std::vector< ast::ptr<ast::Expr> > &, const ast::Decl * ) 49 FORWARD_1( addStructId, const std::string & ) 50 FORWARD_1( addUnionId , const std::string & ) 51 51 52 52 FORWARD_1( globalLookupType, const std::string & ) -
src/Validate/ReplaceTypedef.cpp
r92355883 r2a301ff 20 20 #include "Common/ScopedMap.h" 21 21 #include "Common/UniqueName.h" 22 #include "Common/utility.h"23 22 #include "ResolvExpr/Unify.h" 24 23 … … 294 293 aggrDecl->name, ast::Storage::Classes(), type, aggrDecl->linkage ); 295 294 // Add the implicit typedef to the AST. 296 declsToAdd Before.push_back( ast::deepCopy( typeDecl.get() ) );295 declsToAddAfter.push_back( ast::deepCopy( typeDecl.get() ) ); 297 296 // Shore the name in the map of names. 298 297 typedefNames[ aggrDecl->name ] = … … 316 315 auto mut = ast::mutate( decl ); 317 316 318 std:: vector<ast::ptr<ast::Decl>> members;317 std::list<ast::ptr<ast::Decl>> members; 319 318 // Unroll accept_all for decl->members so that implicit typedefs for 320 319 // nested types are added to the aggregate body. 321 320 for ( ast::ptr<ast::Decl> const & member : mut->members ) { 321 assert( declsToAddBefore.empty() ); 322 322 assert( declsToAddAfter.empty() ); 323 323 ast::Decl const * newMember = nullptr; … … 328 328 } 329 329 if ( !declsToAddBefore.empty() ) { 330 for ( auto declToAdd : declsToAddBefore ) { 331 members.push_back( declToAdd ); 332 } 333 declsToAddBefore.clear(); 330 members.splice( members.end(), declsToAddBefore ); 334 331 } 335 332 members.push_back( newMember ); 336 } 333 if ( !declsToAddAfter.empty() ) { 334 members.splice( members.end(), declsToAddAfter ); 335 } 336 } 337 assert( declsToAddBefore.empty() ); 337 338 assert( declsToAddAfter.empty() ); 338 339 if ( !errors.isEmpty() ) { throw errors; } -
src/Virtual/VirtualDtor.cpp
r92355883 r2a301ff 141 141 auto structIter = structDecls.find( instType->aggr() ); 142 142 if ( structIter == structDecls.end() ) return; 143 144 // If first param not named we need to name it to use it 145 if ( decl->params.at(0)->name == "" ) 146 mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param"; 143 147 144 148 if ( decl->name == "^?{}") { -
src/main.cc
r92355883 r2a301ff 334 334 PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit ); 335 335 336 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit ); 336 337 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit ); 337 338 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit ); … … 342 343 PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit ); 343 344 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit ); 344 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit ); 345 PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit ); 345 PASS( "Fix Unique Ids", Validate::fixUniqueIds, transUnit ); 346 346 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit ); 347 347 … … 370 370 PASS( "Translate Throws", ControlStruct::translateThrows, transUnit ); 371 371 PASS( "Fix Labels", ControlStruct::fixLabels, transUnit ); 372 PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit ); 372 373 PASS( "Fix Names", CodeGen::fixNames, transUnit ); 373 374 PASS( "Gen Init", InitTweak::genInit, transUnit );
Note:
See TracChangeset
for help on using the changeset viewer.