Changes in src/AST/Util.cpp [14c0f7b:0658672]
- File:
-
- 1 edited
-
src/AST/Util.cpp (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Util.cpp
r14c0f7b r0658672 20 20 #include "Pass.hpp" 21 21 #include "TranslationUnit.hpp" 22 #include "Common/utility.h"23 #include "GenPoly/ScopedSet.h"24 22 25 23 #include <vector> 26 27 using GenPoly::ScopedSet;28 24 29 25 namespace ast { … … 106 102 } 107 103 108 /// Check for Floating Nodes:109 /// Every node should be reachable from a root (the TranslationUnit) via a110 /// chain of structural references (tracked with ptr). This cannot check all111 /// 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 119 104 struct InvariantCore { 120 105 // To save on the number of visits: this is a kind of composed core. … … 142 127 } 143 128 144 void previsit( const VariableExpr * node ) {145 previsit( (const ParseNode *)node );146 noFloatingNode( node, &VariableExpr::var );147 }148 149 129 void previsit( const MemberExpr * node ) { 150 130 previsit( (const ParseNode *)node ); 151 131 memberMatchesAggregate( node ); 152 }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 132 } 173 133 … … 177 137 }; 178 138 179 /// Checks that referred to nodes are in scope.180 /// This checks many readonly pointers to see if the declaration they are181 /// 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. at187 // 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 ( isInGlobal220 && 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 the239 // 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->name292 || "__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->name302 || "__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 365 139 } // namespace 366 140 367 141 void checkInvariants( TranslationUnit & transUnit ) { 368 Pass<InvariantCore>::run( transUnit ); 369 Pass<InScopeCore>::run( transUnit ); 142 ast::Pass<InvariantCore>::run( transUnit ); 370 143 } 371 144
Note:
See TracChangeset
for help on using the changeset viewer.