Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Util.cpp

    r14c0f7b r0658672  
    2020#include "Pass.hpp"
    2121#include "TranslationUnit.hpp"
    22 #include "Common/utility.h"
    23 #include "GenPoly/ScopedSet.h"
    2422
    2523#include <vector>
    26 
    27 using GenPoly::ScopedSet;
    2824
    2925namespace ast {
     
    106102}
    107103
    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 
    119104struct InvariantCore {
    120105        // To save on the number of visits: this is a kind of composed core.
     
    142127        }
    143128
    144         void previsit( const VariableExpr * node ) {
    145                 previsit( (const ParseNode *)node );
    146                 noFloatingNode( node, &VariableExpr::var );
    147         }
    148 
    149129        void previsit( const MemberExpr * node ) {
    150130                previsit( (const ParseNode *)node );
    151131                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 );
    172132        }
    173133
     
    177137};
    178138
    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 
    365139} // namespace
    366140
    367141void checkInvariants( TranslationUnit & transUnit ) {
    368         Pass<InvariantCore>::run( transUnit );
    369         Pass<InScopeCore>::run( transUnit );
     142        ast::Pass<InvariantCore>::run( transUnit );
    370143}
    371144
Note: See TracChangeset for help on using the changeset viewer.