Changeset 14c0f7b for src


Ignore:
Timestamp:
Jul 31, 2023, 11:25:51 AM (2 years ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
f496046
Parents:
e0332dd3
Message:

Added invariant to check that referenced declarations are in scope. This one took a while, I don't remember why forall pointer decay is involved.

Location:
src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Create.cpp

    re0332dd3 r14c0f7b  
    4242                return nullptr;
    4343        }
    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;
    5751}
    5852
  • src/AST/Util.cpp

    re0332dd3 r14c0f7b  
    2020#include "Pass.hpp"
    2121#include "TranslationUnit.hpp"
     22#include "Common/utility.h"
     23#include "GenPoly/ScopedSet.h"
    2224
    2325#include <vector>
     26
     27using GenPoly::ScopedSet;
    2428
    2529namespace ast {
     
    173177};
    174178
     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.
     183struct 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
    175365} // namespace
    176366
    177367void checkInvariants( TranslationUnit & transUnit ) {
    178         ast::Pass<InvariantCore>::run( transUnit );
     368        Pass<InvariantCore>::run( transUnit );
     369        Pass<InScopeCore>::run( transUnit );
    179370}
    180371
  • src/InitTweak/InitTweak.cc

    re0332dd3 r14c0f7b  
    891891                                dst = new ast::AddressExpr(dst);
    892892                        }
    893                 }
    894                 else {
     893                } else {
    895894                        dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
    896895                }
     
    900899                        }
    901900                }
    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;
    903906        }
    904907
  • src/SymTab/GenImplicitCall.cpp

    re0332dd3 r14c0f7b  
    1616#include "GenImplicitCall.hpp"
    1717
     18#include "AST/Copy.hpp"                  // for deepCopy
    1819#include "AST/Decl.hpp"                  // for ObjectDecl
    1920#include "AST/Expr.hpp"                  // for ConstantExpr, UntypedExpr,...
     
    115116        std::string cmp, update;
    116117
     118        const ast::Expr * dimension = deepCopy( array->dimension );
    117119        if ( forward ) {
    118120                // generate: for ( int i = 0; i < N; ++i )
    119121                begin = ast::ConstantExpr::from_int( loc, 0 );
    120                 end = array->dimension;
     122                end = dimension;
    121123                cmp = "?<?";
    122124                update = "++?";
     
    124126                // generate: for ( int i = N-1; i >= 0; --i )
    125127                begin = ast::UntypedExpr::createCall( loc, "?-?",
    126                         { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
     128                        { dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
    127129                end = ast::ConstantExpr::from_int( loc, 0 );
    128130                cmp = "?>=?";
  • src/Validate/Autogen.cpp

    re0332dd3 r14c0f7b  
    532532                )
    533533        );
    534         return genImplicitCall(
     534        auto stmt = genImplicitCall(
    535535                srcParam, dstSelect, location, func->name,
    536536                field, direction
    537537        );
     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;
    538550}
    539551
  • src/Validate/FixQualifiedTypes.cpp

    re0332dd3 r14c0f7b  
    8989        }
    9090
    91         ast::Expr const * postvisit( ast::QualifiedNameExpr const * t) {
     91        ast::Expr const * postvisit( ast::QualifiedNameExpr const * t ) {
    9292                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 );
    103101                                }
     102                        } else {
     103                                assertf( false, "unhandled qualified child type" );
    104104                        }
     105                }
    105106
    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 );
    113112        }
    114113
  • src/Validate/ForallPointerDecay.cpp

    re0332dd3 r14c0f7b  
    214214                if ( dynamic_cast< const ast::FunctionType * >( type ) ) return;
    215215                SemanticError( obj->location,
    216                         toCString( "operator ", obj->name.c_str(), " is not "
    217                         "a function or function pointer." ) );
     216                        toCString( "operator ", obj->name.c_str(),
     217                        " is not a function or function pointer." ) );
    218218        }
    219219};
     
    237237        ast::Pass<AssertionFunctionFixer>::run( transUnit );
    238238        ast::Pass<OperatorChecker>::run( transUnit );
     239}
     240
     241void fixUniqueIds( ast::TranslationUnit & transUnit ) {
    239242        ast::Pass<UniqueFixCore>::run( transUnit );
    240243}
  • src/Validate/ForallPointerDecay.hpp

    re0332dd3 r14c0f7b  
    2727
    2828/// 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.
     32void decayForallPointers( ast::TranslationUnit & transUnit );
     33
     34/// Sets uniqueIds on any declarations that do not have one set.
    3135/// Must be after implement concurrent keywords; because uniqueIds must be
    3236/// set on declaration before resolution.
    33 /// Must happen before auto-gen routines are added.
    34 void decayForallPointers( ast::TranslationUnit & transUnit );
     37void fixUniqueIds( ast::TranslationUnit & transUnit );
    3538
    3639/// Expand all traits in an assertion list.
  • src/main.cc

    re0332dd3 r14c0f7b  
    334334                PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit );
    335335
     336                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
    336337                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
    337338                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
     
    342343                PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
    343344                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
    344                 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
     345                PASS( "Fix Unique Ids", Validate::fixUniqueIds, transUnit );
    345346                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
    346347
     
    369370                PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
    370371                PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
    371         PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
     372                PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
    372373                PASS( "Fix Names", CodeGen::fixNames, transUnit );
    373374                PASS( "Gen Init", InitTweak::genInit, transUnit );
Note: See TracChangeset for help on using the changeset viewer.