Changeset b7c53a9d for src


Ignore:
Timestamp:
Jul 14, 2023, 9:32:31 AM (14 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
402a1e7
Parents:
4acf56d
Message:

Added a new invariant check and the fixes required to make it pass. Not the new check is by no means exaustive (it doesn't even check every readonly pointer) but it should catch the most common/problematic cases.

Location:
src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Util.cpp

    r4acf56d rb7c53a9d  
    102102}
    103103
     104/// Check for Floating Nodes:
     105/// Every node should be reachable from a root (the TranslationUnit) via a
     106/// chain of structural references (tracked with ptr). This cannot check all
     107/// of that, it just checks if a given node's field has a strong reference.
     108template<typename node_t, typename field_t>
     109void noFloatingNode( const node_t * node, field_t node_t::*field_ptr ) {
     110        const field_t & field = node->*field_ptr;
     111        if ( nullptr == field ) return;
     112        assertf( field->isManaged(), "Floating node found." );
     113}
     114
    104115struct InvariantCore {
    105116        // To save on the number of visits: this is a kind of composed core.
     
    127138        }
    128139
     140        void previsit( const VariableExpr * node ) {
     141                previsit( (const ParseNode *)node );
     142                noFloatingNode( node, &VariableExpr::var );
     143        }
     144
    129145        void previsit( const MemberExpr * node ) {
    130146                previsit( (const ParseNode *)node );
    131147                memberMatchesAggregate( node );
     148        }
     149
     150        void previsit( const StructInstType * node ) {
     151                previsit( (const Node *)node );
     152                noFloatingNode( node, &StructInstType::base );
     153        }
     154
     155        void previsit( const UnionInstType * node ) {
     156                previsit( (const Node *)node );
     157                noFloatingNode( node, &UnionInstType::base );
     158        }
     159
     160        void previsit( const EnumInstType * node ) {
     161                previsit( (const Node *)node );
     162                noFloatingNode( node, &EnumInstType::base );
     163        }
     164
     165        void previsit( const TypeInstType * node ) {
     166                previsit( (const Node *)node );
     167                noFloatingNode( node, &TypeInstType::base );
    132168        }
    133169
  • src/InitTweak/InitTweak.cc

    r4acf56d rb7c53a9d  
    882882                if (!assign) {
    883883                        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},
    885885                        { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
    886886                          new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
  • src/Validate/ForallPointerDecay.cpp

    r4acf56d rb7c53a9d  
    2323#include "Common/CodeLocation.h"
    2424#include "Common/ToString.hpp"
     25#include "Common/utility.h"
    2526#include "SymTab/FixFunction.h"
    26 
    27 #include "AST/Print.hpp"
    2827
    2928namespace Validate {
     
    5150}
    5251
    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();
     52ast::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;
    6062}
    6163
     
    9698                                        decl->get_type() ) ) {
    9799                                auto moreAsserts = expandTrait( traitInst );
    98                                 append( assertions, moreAsserts );
     100                                splice( assertions, moreAsserts );
    99101                        } else {
    100102                                assertions.push_back( decl );
     
    108110        static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) {
    109111                TypeDeclVec typeDecls;
     112                typeDecls.reserve( old.size() );
    110113                for ( const ast::TypeDecl * typeDecl : old ) {
    111114                        typeDecls.push_back( ast::mutate_field( typeDecl,
     
    123126                mut->assertions = expandAssertions( decl->assertions );
    124127                // 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 );
    133129        }
    134130
     
    154150                const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) {
    155151        std::vector<ast::ptr<ast::DeclWithType>> ret;
     152        ret.reserve( assertions.size() );
    156153        for ( const auto & assn : assertions ) {
    157154                bool isVoid = false;
     
    187184        }
    188185
     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
    189193        const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
    190194                if ( decl->params.empty() ) {
     
    204208};
    205209
    206 struct OberatorChecker final {
     210struct OperatorChecker final {
    207211        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(), " is not "
     217                        "a function or function pointer." ) );
    216218        }
    217219};
     
    234236        ast::Pass<TraitExpander>::run( transUnit );
    235237        ast::Pass<AssertionFunctionFixer>::run( transUnit );
    236         ast::Pass<OberatorChecker>::run( transUnit );
     238        ast::Pass<OperatorChecker>::run( transUnit );
    237239        ast::Pass<UniqueFixCore>::run( transUnit );
    238240}
  • src/Validate/LinkReferenceToTypes.cpp

    r4acf56d rb7c53a9d  
    1010// Created On       : Thr Apr 21 11:41:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Sep 20 16:17:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Jul 14  9:19:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    2727struct LinkTypesCore : public WithNoIdSymbolTable,
    2828                public ast::WithCodeLocation,
     29                public ast::WithDeclsToAdd<>,
    2930                public ast::WithGuards,
    3031                public ast::WithShortCircuiting,
     
    6364        template<typename AggrDecl>
    6465        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 declsToAddBefore once traversal is
     74        /// outside of any namespaces.
     75        void addDeclBeforeOutside( ast::Decl const * );
    6576};
     77
     78void LinkTypesCore::enterNamespace() {
     79        if ( inNamespace ) return;
     80        inNamespace = true;
     81        GuardAction( [this](){
     82                inNamespace = false;
     83                declsToAddBefore.splice( declsToAddBefore.begin(), declsToAddOutside );
     84        } );
     85}
     86
     87void LinkTypesCore::addDeclBeforeOutside( ast::Decl const * decl ) {
     88        if ( inNamespace ) {
     89                declsToAddOutside.emplace_back( decl );
     90        } else {
     91                declsToAddBefore.emplace_back( decl );
     92        }
     93}
    6694
    6795ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
     
    80108ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
    81109        ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
     110        // It's not a semantic error if the enum is not found, just an implicit forward declaration.
     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                decl = new ast::EnumDecl( *location, type->name );
     116                symtab.addEnum( decl );
     117                addDeclBeforeOutside( decl );
     118        }
     119
    82120        ast::EnumInstType * mut = ast::mutate( type );
    83         // It's not a semantic error if the enum is not found, just an implicit forward declaration.
    84         if ( decl ) {
    85                 // Just linking in the node.
    86                 mut->base = decl;
    87         }
    88         if ( !decl || !decl->body ) {
     121
     122        // Just linking in the node.
     123        mut->base = decl;
     124
     125        if ( !decl->body ) {
    89126                forwardEnums[ mut->name ].push_back( mut );
    90127        }
     
    94131ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
    95132        ast::StructDecl const * decl = symtab.lookupStruct( type->name );
     133        // It's not a semantic error if the struct is not found, just an implicit forward declaration.
     134        // The unset code location is used to detect imaginary declarations.
     135        if ( !decl || decl->location.isUnset() ) {
     136                assert( location );
     137                decl = new ast::StructDecl( *location, type->name );
     138                symtab.addStruct( decl );
     139                addDeclBeforeOutside( decl );
     140        }
     141
    96142        ast::StructInstType * mut = ast::mutate( type );
    97         // It's not a semantic error if the struct is not found, just an implicit forward declaration.
    98         if ( decl ) {
    99                 // Just linking in the node.
    100                 mut->base = decl;
    101         }
    102         if ( !decl || !decl->body ) {
     143
     144        // Just linking in the node.
     145        mut->base = decl;
     146
     147        if ( !decl->body ) {
    103148                forwardStructs[ mut->name ].push_back( mut );
    104149        }
     
    108153ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
    109154        ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
     155        // It's not a semantic error if the union is not found, just an implicit forward declaration.
     156        // The unset code location is used to detect imaginary declarations.
     157        if ( !decl || decl->location.isUnset() ) {
     158                assert( location );
     159                decl = new ast::UnionDecl( *location, type->name );
     160                symtab.addUnion( decl );
     161                addDeclBeforeOutside( decl );
     162        }
     163
    110164        ast::UnionInstType * mut = ast::mutate( type );
    111         // It's not a semantic error if the union is not found, just an implicit forward declaration.
    112         if ( decl ) {
    113                 // Just linking in the node.
    114                 mut->base = decl;
    115         }
    116         if ( !decl || !decl->body ) {
     165
     166        // Just linking in the node.
     167        mut->base = decl;
     168
     169        if ( !decl->body ) {
    117170                forwardUnions[ mut->name ].push_back( mut );
    118171        }
     
    219272
    220273ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
     274        enterNamespace();
    221275        return renameGenericParams( decl );
    222276}
     
    237291
    238292ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
     293        enterNamespace();
    239294        return renameGenericParams( decl );
    240295}
  • src/Validate/ReplaceTypedef.cpp

    r4acf56d rb7c53a9d  
    2020#include "Common/ScopedMap.h"
    2121#include "Common/UniqueName.h"
    22 #include "Common/utility.h"
    2322#include "ResolvExpr/Unify.h"
    2423
     
    294293                aggrDecl->name, ast::Storage::Classes(), type, aggrDecl->linkage );
    295294        // Add the implicit typedef to the AST.
    296         declsToAddBefore.push_back( ast::deepCopy( typeDecl.get() ) );
     295        declsToAddAfter.push_back( ast::deepCopy( typeDecl.get() ) );
    297296        // Shore the name in the map of names.
    298297        typedefNames[ aggrDecl->name ] =
     
    316315        auto mut = ast::mutate( decl );
    317316
    318         std::vector<ast::ptr<ast::Decl>> members;
     317        std::list<ast::ptr<ast::Decl>> members;
    319318        // Unroll accept_all for decl->members so that implicit typedefs for
    320319        // nested types are added to the aggregate body.
    321320        for ( ast::ptr<ast::Decl> const & member : mut->members ) {
     321                assert( declsToAddBefore.empty() );
    322322                assert( declsToAddAfter.empty() );
    323323                ast::Decl const * newMember = nullptr;
     
    328328                }
    329329                if ( !declsToAddBefore.empty() ) {
    330                         for ( auto declToAdd : declsToAddBefore ) {
    331                                 members.push_back( declToAdd );
    332                         }
    333                         declsToAddBefore.clear();
     330                        members.splice( members.end(), declsToAddBefore );
    334331                }
    335332                members.push_back( newMember );
    336         }
     333                if ( !declsToAddAfter.empty() ) {
     334                        members.splice( members.end(), declsToAddAfter );
     335                }
     336        }
     337        assert( declsToAddBefore.empty() );
    337338        assert( declsToAddAfter.empty() );
    338339        if ( !errors.isEmpty() ) { throw errors; }
Note: See TracChangeset for help on using the changeset viewer.