Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    rf02f546 rfb4dc28  
    300300
    301301#       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
    304302        struct HoistArrayDimension_NoResolve_New final :
    305303                        public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
    306304                        public ast::WithGuards, public ast::WithConstTranslationUnit,
    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(
     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 );
     314
     315                ast::Storage::Classes storageClasses;
     316        };
     317
     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(
    423355                                        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
    440 
    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                 }
    461         };
    462 
    463 
    464 
     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        }
    465370
    466371        struct ReturnFixer_New final :
Note: See TracChangeset for help on using the changeset viewer.