Changeset 8984003 for src/InitTweak


Ignore:
Timestamp:
Nov 21, 2023, 4:47:58 PM (7 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
53dac82
Parents:
c36a419
Message:

Round of significant clean-up and reindentation of InitTweak? directory.

Location:
src/InitTweak
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixGlobalInit.cc

    rc36a419 r8984003  
    2727
    2828namespace InitTweak {
    29         class GlobalFixer : public ast::WithShortCircuiting {
    30         public:
    31                 void previsit (const ast::ObjectDecl *);
    32                 void previsit (const ast::FunctionDecl *) { visit_children = false; }
    33                 void previsit (const ast::StructDecl *) { visit_children = false; }
    34                 void previsit (const ast::UnionDecl *) { visit_children = false; }
    35                 void previsit (const ast::EnumDecl *) { visit_children = false; }
    36                 void previsit (const ast::TraitDecl *) { visit_children = false; }
    37                 void previsit (const ast::TypeDecl *) { visit_children = false; }
    3829
    39                 std::list< ast::ptr<ast::Stmt> > initStmts;
    40                 std::list< ast::ptr<ast::Stmt> > destroyStmts;
    41         };
     30namespace {
    4231
    43         void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
    44                 ast::Pass<GlobalFixer> fixer;
    45                 accept_all(translationUnit, fixer);
     32class GlobalFixer : public ast::WithShortCircuiting {
     33public:
     34        void previsit(const ast::ObjectDecl *);
     35        void previsit(const ast::FunctionDecl *) { visit_children = false; }
     36        void previsit(const ast::StructDecl *) { visit_children = false; }
     37        void previsit(const ast::UnionDecl *) { visit_children = false; }
     38        void previsit(const ast::EnumDecl *) { visit_children = false; }
     39        void previsit(const ast::TraitDecl *) { visit_children = false; }
     40        void previsit(const ast::TypeDecl *) { visit_children = false; }
    4641
    47                 // Say these magic declarations come at the end of the file.
    48                 CodeLocation const & location = translationUnit.decls.back()->location;
     42        std::list< ast::ptr<ast::Stmt> > initStmts;
     43        std::list< ast::ptr<ast::Stmt> > destroyStmts;
     44};
    4945
    50                 if ( !fixer.core.initStmts.empty() ) {
    51                         std::vector<ast::ptr<ast::Expr>> ctorParams;
    52                         if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
    53                         auto initFunction = new ast::FunctionDecl(location,
    54                                 "__global_init__", {}, {}, {},
    55                                 new ast::CompoundStmt(location, std::move(fixer.core.initStmts)),
    56                                 ast::Storage::Static, ast::Linkage::C,
    57                                 {new ast::Attribute("constructor", std::move(ctorParams))});
     46void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) {
     47        auto mutDecl = mutate(objDecl);
     48        assertf(mutDecl == objDecl, "Global object decl must be unique");
     49        auto ctorInit = objDecl->init.as<ast::ConstructorInit>();
     50        if ( nullptr == ctorInit ) return;
    5851
    59                         translationUnit.decls.emplace_back( initFunction );
    60                 } // if
     52        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     53        assert( !ctorInit->ctor || !ctorInit->init );
    6154
    62                 if ( !fixer.core.destroyStmts.empty() ) {
    63                         std::vector<ast::ptr<ast::Expr>> dtorParams;
    64                         if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
    65                         auto destroyFunction = new ast::FunctionDecl( location,
    66                                 "__global_destroy__", {}, {}, {},
    67                                 new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)),
    68                                 ast::Storage::Static, ast::Linkage::C,
    69                                 {new ast::Attribute("destructor", std::move(dtorParams))});
     55        const ast::Stmt * dtor = ctorInit->dtor;
     56        if ( dtor && !isIntrinsicSingleArgCallStmt( dtor ) ) {
     57                // don't need to call intrinsic dtor, because it does nothing, but
     58                // non-intrinsic dtors must be called
     59                destroyStmts.push_front( dtor );
     60        } // if
     61        if ( const ast::Stmt * ctor = ctorInit->ctor ) {
     62                addDataSectionAttribute(mutDecl);
     63                initStmts.push_back( ctor );
     64                mutDecl->init = nullptr;
     65        } else if ( const ast::Init * init = ctorInit->init ) {
     66                mutDecl->init = init;
     67        } else {
     68                // no constructor and no initializer, which is okay
     69                mutDecl->init = nullptr;
     70        }
     71}
    7072
    71                         translationUnit.decls.emplace_back(destroyFunction);
    72                 } // if
    73         }
     73} // namespace
    7474
    75         void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) {
    76                 auto mutDecl = mutate(objDecl);
    77                 assertf(mutDecl == objDecl, "Global object decl must be unique");
    78                 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) {
    79                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    80                         assert( ! ctorInit->ctor || ! ctorInit->init );
     75void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
     76        ast::Pass<GlobalFixer> fixer;
     77        accept_all(translationUnit, fixer);
    8178
    82                         const ast::Stmt * dtor = ctorInit->dtor;
    83                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    84                                 // don't need to call intrinsic dtor, because it does nothing, but
    85                                 // non-intrinsic dtors must be called
    86                                 destroyStmts.push_front( dtor );
    87                                 // ctorInit->dtor = nullptr;
    88                         } // if
    89                         if ( const ast::Stmt * ctor = ctorInit->ctor ) {
    90                                 addDataSectionAttribute(mutDecl);
    91                                 initStmts.push_back( ctor );
    92                                 mutDecl->init = nullptr;
    93                                 // ctorInit->ctor = nullptr;
    94                         } else if ( const ast::Init * init = ctorInit->init ) {
    95                                 mutDecl->init = init;
    96                                 // ctorInit->init = nullptr;
    97                         } else {
    98                                 // no constructor and no initializer, which is okay
    99                                 mutDecl->init = nullptr;
    100                         } // if
    101                         // delete ctorInit;
    102                 } // if
    103         }
     79        // Say these magic declarations come at the end of the file.
     80        CodeLocation const & location = translationUnit.decls.back()->location;
     81
     82        if ( !fixer.core.initStmts.empty() ) {
     83                std::vector<ast::ptr<ast::Expr>> ctorParams;
     84                if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
     85                auto initFunction = new ast::FunctionDecl(location,
     86                        "__global_init__", {}, {}, {},
     87                        new ast::CompoundStmt(location, std::move(fixer.core.initStmts)),
     88                        ast::Storage::Static, ast::Linkage::C,
     89                        {new ast::Attribute("constructor", std::move(ctorParams))});
     90
     91                translationUnit.decls.emplace_back( initFunction );
     92        } // if
     93
     94        if ( !fixer.core.destroyStmts.empty() ) {
     95                std::vector<ast::ptr<ast::Expr>> dtorParams;
     96                if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
     97                auto destroyFunction = new ast::FunctionDecl( location,
     98                        "__global_destroy__", {}, {}, {},
     99                        new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)),
     100                        ast::Storage::Static, ast::Linkage::C,
     101                        {new ast::Attribute("destructor", std::move(dtorParams))});
     102
     103                translationUnit.decls.emplace_back(destroyFunction);
     104        } // if
     105}
    104106
    105107} // namespace InitTweak
  • src/InitTweak/FixGlobalInit.h

    rc36a419 r8984003  
    1616#pragma once
    1717
    18 #include <list>    // for list
    19 #include <string>  // for string
    20 
    21 #include <AST/Fwd.hpp>
    22 
    23 
    24 class Declaration;
     18namespace ast {
     19        class TranslationUnit;
     20}
    2521
    2622namespace InitTweak {
    27         /// Moves global initialization into an _init function that is unique to the translation unit.
    28         /// Sets the priority of the initialization function depending on whether the initialization
    29         /// function is for library code.
    30         void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary );
    31         void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
     23
     24/// Moves global initialization into an _init function that is unique to the translation unit.
     25/// Sets the priority of the initialization function depending on whether the initialization
     26/// function is for library code.
     27void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
     28
    3229} // namespace
    3330
  • src/InitTweak/FixInit.h

    rc36a419 r8984003  
    1616#pragma once
    1717
    18 #include <list>    // for list
    19 #include <string>  // for string
    20 
    21 class Declaration;
    2218namespace ast {
    2319        class TranslationUnit;
     
    2521
    2622namespace InitTweak {
    27         /// replace constructor initializers with expression statements and unwrap basic C-style initializers
    28         void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
    2923
    30         void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
     24/// Replace constructor initializers with expression statements and unwrap basic C-style initializers.
     25void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
     26
    3127} // namespace
    3228
  • src/InitTweak/GenInit.cc

    rc36a419 r8984003  
    206206        };
    207207
    208 
    209 
    210 
    211208        struct ReturnFixer final :
    212209                        public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
     
    262259} // namespace
    263260
    264         void genInit( ast::TranslationUnit & transUnit ) {
    265                 ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit );
    266                 ast::Pass<ReturnFixer>::run( transUnit );
    267         }
    268 
    269         void fixReturnStatements( ast::TranslationUnit & transUnit ) {
    270                 ast::Pass<ReturnFixer>::run( transUnit );
    271         }
    272 
    273         bool ManagedTypes::isManaged( const ast::Type * type ) const {
    274                 // references are never constructed
    275                 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
    276                 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
    277                         // tuple is also managed if any of its components are managed
    278                         for (auto & component : tupleType->types) {
    279                                 if (isManaged(component)) return true;
    280                         }
    281                 }
    282                 // need to clear and reset qualifiers when determining if a type is managed
    283                 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
    284                 auto tmp = shallowCopy(type);
    285                 tmp->qualifiers = {};
    286                 // delete tmp at return
    287                 ast::ptr<ast::Type> guard = tmp;
    288                 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
    289                 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
    290         }
    291 
    292         bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const {
    293                 const ast::Type * type = objDecl->type;
    294                 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
    295                         // must always construct VLAs with an initializer, since this is an error in C
    296                         if ( at->isVarLen && objDecl->init ) return true;
    297                         type = at->base;
    298                 }
    299                 return isManaged( type );
    300         }
    301 
    302         void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) {
    303                 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
    304                 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
    305                         auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
    306                         assert( ! params.empty() );
    307                         // Type * type = InitTweak::getPointerBase( params.front() );
    308                         // assert( type );
    309                         managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
    310                 }
    311         }
    312 
    313         void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) {
    314                 // don't construct members, but need to take note if there is a managed member,
    315                 // because that means that this type is also managed
    316                 for ( auto & member : aggregateDecl->members ) {
    317                         if ( auto field = member.as<ast::ObjectDecl>() ) {
    318                                 if ( isManaged( field ) ) {
    319                                         // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
    320                                         // polymorphic constructors make generic types managed types
    321                                         ast::StructInstType inst( aggregateDecl );
    322                                         managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
    323                                         break;
    324                                 }
    325                         }
    326                 }
    327         }
    328 
    329         void ManagedTypes::beginScope() { managedTypes.beginScope(); }
    330         void ManagedTypes::endScope() { managedTypes.endScope(); }
    331 
    332         ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
    333                 assertf(objDecl, "genCtorDtor passed null objDecl");
    334                 InitExpander srcParam(arg);
    335                 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    336         }
     261void genInit( ast::TranslationUnit & transUnit ) {
     262        ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit );
     263        ast::Pass<ReturnFixer>::run( transUnit );
     264}
     265
     266void fixReturnStatements( ast::TranslationUnit & transUnit ) {
     267        ast::Pass<ReturnFixer>::run( transUnit );
     268}
     269
     270bool ManagedTypes::isManaged( const ast::Type * type ) const {
     271        // references are never constructed
     272        if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
     273        if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
     274                // tuple is also managed if any of its components are managed
     275                for (auto & component : tupleType->types) {
     276                        if (isManaged(component)) return true;
     277                }
     278        }
     279        // need to clear and reset qualifiers when determining if a type is managed
     280        // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
     281        auto tmp = shallowCopy(type);
     282        tmp->qualifiers = {};
     283        // delete tmp at return
     284        ast::ptr<ast::Type> guard = tmp;
     285        // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
     286        return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
     287}
     288
     289bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const {
     290        const ast::Type * type = objDecl->type;
     291        while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
     292                // must always construct VLAs with an initializer, since this is an error in C
     293                if ( at->isVarLen && objDecl->init ) return true;
     294                type = at->base;
     295        }
     296        return isManaged( type );
     297}
     298
     299void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) {
     300        // if this function is a user-defined constructor or destructor, mark down the type as "managed"
     301        if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
     302                auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
     303                assert( ! params.empty() );
     304                // Type * type = InitTweak::getPointerBase( params.front() );
     305                // assert( type );
     306                managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
     307        }
     308}
     309
     310void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) {
     311        // don't construct members, but need to take note if there is a managed member,
     312        // because that means that this type is also managed
     313        for ( auto & member : aggregateDecl->members ) {
     314                if ( auto field = member.as<ast::ObjectDecl>() ) {
     315                        if ( isManaged( field ) ) {
     316                                // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
     317                                // polymorphic constructors make generic types managed types
     318                                ast::StructInstType inst( aggregateDecl );
     319                                managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
     320                                break;
     321                        }
     322                }
     323        }
     324}
     325
     326void ManagedTypes::beginScope() { managedTypes.beginScope(); }
     327void ManagedTypes::endScope() { managedTypes.endScope(); }
     328
     329ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
     330        assertf(objDecl, "genCtorDtor passed null objDecl");
     331        InitExpander srcParam(arg);
     332        return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
     333}
    337334
    338335ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
  • src/InitTweak/GenInit.h

    rc36a419 r8984003  
    2424
    2525namespace InitTweak {
    26         /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
    27         void genInit( ast::TranslationUnit & translationUnit );
    2826
    29         /// Converts return statements into copy constructor calls on the hidden return variable.
    30         /// This pass must happen before auto-gen.
    31         void fixReturnStatements( ast::TranslationUnit & translationUnit );
     27/// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
     28void genInit( ast::TranslationUnit & translationUnit );
    3229
    33         /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    34         ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
     30/// Converts return statements into copy constructor calls on the hidden return variable.
     31/// This pass must happen before auto-gen.
     32void fixReturnStatements( ast::TranslationUnit & translationUnit );
    3533
    36         /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
    37         ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
     34/// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
     35ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3836
    39         class ManagedTypes final {
    40         public:
    41                 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
    42                 bool isManaged( const ast::Type * type ) const; // determine if type is managed
     37/// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
     38ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
    4339
    44                 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
    45                 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
     40class ManagedTypes final {
     41public:
     42        bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
     43        bool isManaged( const ast::Type * type ) const; // determine if type is managed
    4644
    47                 void beginScope();
    48                 void endScope();
    49         private:
    50                 GenPoly::ScopedSet< std::string > managedTypes;
    51         };
     45        void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
     46        void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
     47
     48        void beginScope();
     49        void endScope();
     50private:
     51        GenPoly::ScopedSet< std::string > managedTypes;
     52};
     53
    5254} // namespace
    5355
  • src/InitTweak/InitTweak.cc

    rc36a419 r8984003  
    1414//
    1515
     16#include "InitTweak.h"
     17
    1618#include <algorithm>               // for find, all_of
    1719#include <cassert>                 // for assertf, assert, strict_dynamic_cast
     
    3032#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
    3133#include "Common/SemanticError.h"  // for SemanticError
     34#include "Common/ToString.hpp"     // for toCString
    3235#include "Common/UniqueName.h"     // for UniqueName
    33 #include "Common/utility.h"        // for toString, deleteAll, maybeClone
    3436#include "GenPoly/GenPoly.h"       // for getFunctionType
    35 #include "InitTweak.h"
    3637#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
    3738#include "Tuples/Tuples.h"         // for Tuples::isTtype
    3839
    3940namespace InitTweak {
    40         namespace {
    41                 struct HasDesignations : public ast::WithShortCircuiting {
    42                         bool result = false;
    43 
    44                         void previsit( const ast::Node * ) {
    45                                 // short circuit if we already know there are designations
    46                                 if ( result ) visit_children = false;
    47                         }
    48 
    49                         void previsit( const ast::Designation * des ) {
    50                                 // short circuit if we already know there are designations
    51                                 if ( result ) visit_children = false;
    52                                 else if ( ! des->designators.empty() ) {
    53                                         result = true;
    54                                         visit_children = false;
    55                                 }
    56                         }
    57                 };
    58 
    59                 struct InitDepthChecker {
    60                         bool result = true;
    61                         const ast::Type * type;
    62                         int curDepth = 0, maxDepth = 0;
    63                         InitDepthChecker( const ast::Type * type ) : type( type ) {
    64                                 const ast::Type * t = type;
    65                                 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
    66                                         maxDepth++;
    67                                         t = at->base;
    68                                 }
    69                                 maxDepth++;
    70                         }
    71                         void previsit( ast::ListInit const * ) {
    72                                 curDepth++;
    73                                 if ( curDepth > maxDepth ) result = false;
    74                         }
    75                         void postvisit( ast::ListInit const * ) {
    76                                 curDepth--;
    77                         }
    78                 };
    79 
    80                 struct InitFlattener : public ast::WithShortCircuiting {
    81                         std::vector< ast::ptr< ast::Expr > > argList;
    82 
    83                         void previsit( const ast::SingleInit * singleInit ) {
    84                                 visit_children = false;
    85                                 argList.emplace_back( singleInit->value );
    86                         }
    87                 };
    88 
    89         } // anonymous namespace
    90 
    91         bool isDesignated( const ast::Init * init ) {
    92                 ast::Pass<HasDesignations> finder;
    93                 maybe_accept( init, finder );
    94                 return finder.core.result;
    95         }
    96 
    97         bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
    98                 ast::Pass<InitDepthChecker> checker( objDecl->type );
    99                 maybe_accept( objDecl->init.get(), checker );
    100                 return checker.core.result;
    101         }
    102 
    103 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
    104         ast::Pass< InitFlattener > flattener;
    105         maybe_accept( init, flattener );
    106         return std::move( flattener.core.argList );
    107 }
    108 
     41
     42// Forward declared, because it is used as a parent type.
    10943class InitExpander::ExpanderImpl {
    11044public:
     
    11650
    11751namespace {
     52        struct HasDesignations : public ast::WithShortCircuiting {
     53                bool result = false;
     54
     55                void previsit( const ast::Node * ) {
     56                        // Short circuit if we already know there are designations.
     57                        if ( result ) visit_children = false;
     58                }
     59
     60                void previsit( const ast::Designation * des ) {
     61                        // Short circuit if we already know there are designations.
     62                        if ( result ) visit_children = false;
     63                        else if ( !des->designators.empty() ) {
     64                                result = true;
     65                                visit_children = false;
     66                        }
     67                }
     68        };
     69
     70        struct InitDepthChecker {
     71                bool result = true;
     72                const ast::Type * type;
     73                int curDepth = 0, maxDepth = 0;
     74                InitDepthChecker( const ast::Type * type ) : type( type ) {
     75                        const ast::Type * t = type;
     76                        while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
     77                                maxDepth++;
     78                                t = at->base;
     79                        }
     80                        maxDepth++;
     81                }
     82                void previsit( ast::ListInit const * ) {
     83                        curDepth++;
     84                        if ( curDepth > maxDepth ) result = false;
     85                }
     86                void postvisit( ast::ListInit const * ) {
     87                        curDepth--;
     88                }
     89        };
     90
     91        struct InitFlattener : public ast::WithShortCircuiting {
     92                std::vector< ast::ptr< ast::Expr > > argList;
     93
     94                void previsit( const ast::SingleInit * singleInit ) {
     95                        visit_children = false;
     96                        argList.emplace_back( singleInit->value );
     97                }
     98        };
     99
    118100        template< typename Out >
    119101        void buildCallExpr(
     
    223205                        InitExpander::IndexList & indices
    224206                ) override {
    225                         if ( ! arg ) return {};
     207                        if ( !arg ) return {};
    226208
    227209                        const CodeLocation & loc = arg->location;
    228210                        const ast::Expr * expr = arg;
    229211                        for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) {
    230                                 // go through indices and layer on subscript exprs ?[?]
     212                                // Go through indices and layer on subscript exprs ?[?].
    231213                                ++it;
    232214                                expr = new ast::UntypedExpr{
     
    242224                }
    243225        };
    244 } // anonymous namespace
    245 
    246 InitExpander::InitExpander( const ast::Init * init )
    247 : expander( new InitImpl{ init } ), crnt(), indices() {}
    248 
    249 InitExpander::InitExpander( const ast::Expr * expr )
    250 : expander( new ExprImpl{ expr } ), crnt(), indices() {}
    251 
    252 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
    253 
    254 InitExpander & InitExpander::operator++ () {
    255         crnt = expander->next( indices );
    256         return *this;
    257 }
    258 
    259 /// builds statement which has the same semantics as a C-style list initializer (for array
    260 /// initializers) using callExpr as the base expression to perform initialization
    261 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
    262         return expander->buildListInit( callExpr, indices );
    263 }
    264 
    265 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
    266         indices.emplace_back( index );
    267         indices.emplace_back( dimension );
    268 }
    269 
    270 void InitExpander::clearArrayIndices() { indices.clear(); }
    271 
    272 bool InitExpander::addReference() {
    273         for ( ast::ptr< ast::Expr > & expr : crnt ) {
    274                 expr = new ast::AddressExpr{ expr };
    275         }
    276         return ! crnt.empty();
    277 }
    278 
    279         const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
    280                 assertf( ftype, "getTypeofThis: nullptr ftype" );
    281                 const std::vector<ast::ptr<ast::Type>> & params = ftype->params;
    282                 assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",
    283                                 toString( ftype ).c_str() );
    284                 const ast::ReferenceType * refType =
    285                         params.front().strict_as<ast::ReferenceType>();
    286                 return refType->base;
    287         }
    288 
    289         const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
    290                 assertf( func, "getParamThis: nullptr ftype" );
    291                 auto & params = func->params;
    292                 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
    293                 return params.front().strict_as<ast::ObjectDecl>();
    294         }
    295 
    296         bool tryConstruct( const ast::DeclWithType * dwt ) {
    297                 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
    298                 if ( ! objDecl ) return false;
    299                 return (objDecl->init == nullptr ||
    300                                 ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
    301                         && ! objDecl->storage.is_extern
    302                         && isConstructable( objDecl->type );
    303         }
    304 
    305         bool isConstructable( const ast::Type * type ) {
    306                 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )
    307                 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );
    308         }
    309226
    310227        struct CallFinder final {
     
    325242        };
    326243
    327         std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    328                 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    329                 maybe_accept( stmt, finder );
    330                 return std::move( finder.core.matches );
    331         }
    332 
    333         namespace {
    334                 template <typename Predicate>
    335                 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
    336                         std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
    337                         return std::all_of( callExprs.begin(), callExprs.end(), pred );
    338                 }
    339         }
    340 
    341         bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
    342                 return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
    343                         if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
    344                                 const ast::FunctionType * funcType =
    345                                         GenPoly::getFunctionType( appExpr->func->result );
    346                                 assert( funcType );
    347                                 return funcType->params.size() == 1;
    348                         }
    349                         return false;
    350                 });
    351         }
    352 
    353         // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
    354         // following passes may accidentally resolve this expression if returned as untyped...
    355         ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) {
    356                 static ast::ptr<ast::FunctionDecl> assign = nullptr;
    357                 if (!assign) {
    358                         auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
    359                         assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td},
    360                         { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
    361                           new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
    362                         { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
    363                 }
    364                 if (dst->result.as<ast::ReferenceType>()) {
    365                         for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
    366                                 dst = new ast::AddressExpr(dst);
    367                         }
    368                 } else {
    369                         dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
    370                 }
    371                 if (src->result.as<ast::ReferenceType>()) {
    372                         for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
    373                                 src = new ast::AddressExpr(src);
    374                         }
    375                 }
    376                 auto var = ast::VariableExpr::functionPointer(dst->location, assign);
    377                 auto app = new ast::ApplicationExpr(dst->location, var, {dst, src});
    378                 // Skip the resolver, just set the result to the correct type.
    379                 app->result = ast::deepCopy( src->result );
    380                 return app;
     244        template <typename Predicate>
     245        bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
     246                std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
     247                return std::all_of( callExprs.begin(), callExprs.end(), pred );
    381248        }
    382249
    383250        struct ConstExprChecker : public ast::WithShortCircuiting {
    384                 // most expressions are not const expr
     251                // Most expressions are not const-expr.
    385252                void previsit( const ast::Expr * ) { result = false; visit_children = false; }
    386253
     
    389256                        const ast::Expr * arg = addressExpr->arg;
    390257
    391                         // address of a variable or member expression is constexpr
    392                         if ( ! dynamic_cast< const ast::NameExpr * >( arg )
    393                         && ! dynamic_cast< const ast::VariableExpr * >( arg )
    394                         && ! dynamic_cast< const ast::MemberExpr * >( arg )
    395                         && ! dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
    396                 }
    397 
    398                 // these expressions may be const expr, depending on their children
     258                        // Address of a variable or member expression is const-expr.
     259                        if ( !dynamic_cast< const ast::NameExpr * >( arg )
     260                                && !dynamic_cast< const ast::VariableExpr * >( arg )
     261                                && !dynamic_cast< const ast::MemberExpr * >( arg )
     262                                && !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
     263                }
     264
     265                // These expressions may be const expr, depending on their children.
    399266                void previsit( const ast::SizeofExpr * ) {}
    400267                void previsit( const ast::AlignofExpr * ) {}
     
    423290                bool result = true;
    424291        };
    425 
    426         bool isConstExpr( const ast::Expr * expr ) {
    427                 if ( expr ) {
    428                         ast::Pass<ConstExprChecker> checker;
    429                         expr->accept( checker );
    430                         return checker.core.result;
    431                 }
    432                 return true;
    433         }
    434 
    435         bool isConstExpr( const ast::Init * init ) {
    436                 if ( init ) {
    437                         ast::Pass<ConstExprChecker> checker;
    438                         init->accept( checker );
    439                         return checker.core.result;
    440                 } // if
    441                 // for all intents and purposes, no initializer means const expr
    442                 return true;
    443         }
     292} // namespace
    444293
    445294bool isAssignment( const ast::FunctionDecl * decl ) {
     
    470319}
    471320
    472         #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
    473                 #define ASM_COMMENT "#"
    474         #else // defined( __ARM_ARCH )
    475                 #define ASM_COMMENT "//"
    476         #endif
    477         static const char * const data_section =  ".data" ASM_COMMENT;
    478         static const char * const tlsd_section = ".tdata" ASM_COMMENT;
    479 
    480         void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
    481                 const bool is_tls = objDecl->storage.is_threadlocal_any();
    482                 const char * section = is_tls ? tlsd_section : data_section;
    483                 objDecl->attributes.push_back(new ast::Attribute("section", {
    484                         ast::ConstantExpr::from_string(objDecl->location, section)
    485                 }));
    486         }
     321const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
     322        assertf( ftype, "getTypeofThis: nullptr ftype" );
     323        const std::vector<ast::ptr<ast::Type>> & params = ftype->params;
     324        assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",
     325                        toCString( ftype ) );
     326        const ast::ReferenceType * refType =
     327                params.front().strict_as<ast::ReferenceType>();
     328        return refType->base;
     329}
     330
     331const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
     332        assertf( func, "getParamThis: nullptr ftype" );
     333        auto & params = func->params;
     334        assertf( !params.empty(), "getParamThis: ftype with 0 parameters: %s", toCString( func ));
     335        return params.front().strict_as<ast::ObjectDecl>();
     336}
     337
     338// looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
     339// following passes may accidentally resolve this expression if returned as untyped...
     340ast::Expr * createBitwiseAssignment(const ast::Expr * dst, const ast::Expr * src) {
     341        static ast::ptr<ast::FunctionDecl> assign = nullptr;
     342        if (!assign) {
     343                auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
     344                assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td},
     345                { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
     346                  new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
     347                { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
     348        }
     349        if (dst->result.as<ast::ReferenceType>()) {
     350                for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
     351                        dst = new ast::AddressExpr(dst);
     352                }
     353        } else {
     354                dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
     355        }
     356        if (src->result.as<ast::ReferenceType>()) {
     357                for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
     358                        src = new ast::AddressExpr(src);
     359                }
     360        }
     361        auto var = ast::VariableExpr::functionPointer(dst->location, assign);
     362        auto app = new ast::ApplicationExpr(dst->location, var, {dst, src});
     363        // Skip the resolver, just set the result to the correct type.
     364        app->result = ast::deepCopy( src->result );
     365        return app;
     366}
     367
     368std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
     369        ast::Pass< InitFlattener > flattener;
     370        maybe_accept( init, flattener );
     371        return std::move( flattener.core.argList );
     372}
     373
     374bool tryConstruct( const ast::DeclWithType * dwt ) {
     375        auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
     376        if ( !objDecl ) return false;
     377        return (objDecl->init == nullptr ||
     378                        ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
     379                && !objDecl->storage.is_extern
     380                && isConstructable( objDecl->type );
     381}
     382
     383bool isConstructable( const ast::Type * type ) {
     384        return !dynamic_cast< const ast::VarArgsType * >( type ) && !dynamic_cast< const ast::ReferenceType * >( type )
     385                && !dynamic_cast< const ast::FunctionType * >( type ) && !Tuples::isTtype( type );
     386}
     387
     388bool isDesignated( const ast::Init * init ) {
     389//      return ( init ) ? ast::Pass<HasDesignations>::read( init ) : false;
     390        ast::Pass<HasDesignations> finder;
     391        maybe_accept( init, finder );
     392        return finder.core.result;
     393}
     394
     395bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
     396//      return ( objDecl->init ) ? ast::Pass<InitDepthChecker::read( objDecl->init, objDecl->type ) : true;
     397        ast::Pass<InitDepthChecker> checker( objDecl->type );
     398        maybe_accept( objDecl->init.get(), checker );
     399        return checker.core.result;
     400}
     401
     402bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
     403        return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
     404                if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
     405                        const ast::FunctionType * funcType =
     406                                GenPoly::getFunctionType( appExpr->func->result );
     407                        assert( funcType );
     408                        return funcType->params.size() == 1;
     409                }
     410                return false;
     411        });
     412}
     413
     414std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     415        ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
     416        maybe_accept( stmt, finder );
     417        return std::move( finder.core.matches );
     418}
     419
     420bool isConstExpr( const ast::Expr * expr ) {
     421        return ( expr ) ? ast::Pass<ConstExprChecker>::read( expr ) : true;
     422}
     423
     424bool isConstExpr( const ast::Init * init ) {
     425        // for all intents and purposes, no initializer means const expr
     426        return ( init ) ? ast::Pass<ConstExprChecker>::read( init ) : true;
     427}
     428
     429#if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
     430        #define ASM_COMMENT "#"
     431#else // defined( __ARM_ARCH )
     432        #define ASM_COMMENT "//"
     433#endif
     434static const char * const data_section =  ".data" ASM_COMMENT;
     435static const char * const tlsd_section = ".tdata" ASM_COMMENT;
     436
     437void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
     438        const bool is_tls = objDecl->storage.is_threadlocal_any();
     439        const char * section = is_tls ? tlsd_section : data_section;
     440        objDecl->attributes.push_back(new ast::Attribute("section", {
     441                ast::ConstantExpr::from_string(objDecl->location, section)
     442        }));
     443}
     444
     445InitExpander::InitExpander( const ast::Init * init )
     446: expander( new InitImpl{ init } ), crnt(), indices() {}
     447
     448InitExpander::InitExpander( const ast::Expr * expr )
     449: expander( new ExprImpl{ expr } ), crnt(), indices() {}
     450
     451std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
     452
     453InitExpander & InitExpander::operator++ () {
     454        crnt = expander->next( indices );
     455        return *this;
     456}
     457
     458/// builds statement which has the same semantics as a C-style list initializer (for array
     459/// initializers) using callExpr as the base expression to perform initialization
     460ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
     461        return expander->buildListInit( callExpr, indices );
     462}
     463
     464void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
     465        indices.emplace_back( index );
     466        indices.emplace_back( dimension );
     467}
     468
     469void InitExpander::clearArrayIndices() { indices.clear(); }
     470
     471bool InitExpander::addReference() {
     472        for ( ast::ptr< ast::Expr > & expr : crnt ) {
     473                expr = new ast::AddressExpr{ expr };
     474        }
     475        return !crnt.empty();
     476}
    487477
    488478} // namespace InitTweak
  • src/InitTweak/InitTweak.h

    rc36a419 r8984003  
    2525// helper functions for initialization
    2626namespace InitTweak {
    27         bool isAssignment( const ast::FunctionDecl * decl );
    28         bool isDestructor( const ast::FunctionDecl * decl );
    29         bool isDefaultConstructor( const ast::FunctionDecl * decl );
    30         bool isCopyConstructor( const ast::FunctionDecl * decl );
    31         bool isCopyFunction( const ast::FunctionDecl * decl );
    3227
    33         /// returns the base type of the first parameter to a constructor/destructor/assignment function
    34         const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
     28bool isAssignment( const ast::FunctionDecl * decl );
     29bool isDestructor( const ast::FunctionDecl * decl );
     30bool isDefaultConstructor( const ast::FunctionDecl * decl );
     31bool isCopyConstructor( const ast::FunctionDecl * decl );
     32bool isCopyFunction( const ast::FunctionDecl * decl );
    3533
    36         /// returns the first parameter of a constructor/destructor/assignment function
    37         const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
     34/// returns the base type of the first parameter to a constructor/destructor/assignment function
     35const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
    3836
    39         /// generate a bitwise assignment operation.
    40         ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
     37/// returns the first parameter of a constructor/destructor/assignment function
     38const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4139
    42         /// transform Initializer into an argument list that can be passed to a call expression
    43         std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
     40/// generate a bitwise assignment operation.
     41ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4442
    45         /// True if the resolver should try to construct dwt
    46         bool tryConstruct( const ast::DeclWithType * dwt );
     43/// transform Initializer into an argument list that can be passed to a call expression
     44std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    4745
    48         /// True if the type can have a user-defined constructor
    49         bool isConstructable( const ast::Type * t );
     46/// True if the resolver should try to construct dwt
     47bool tryConstruct( const ast::DeclWithType * dwt );
    5048
    51         /// True if the Initializer contains designations
    52         bool isDesignated( const ast::Init * init );
     49/// True if the type can have a user-defined constructor
     50bool isConstructable( const ast::Type * t );
    5351
    54         /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    55         /// type, where the depth of its type is the number of nested ArrayTypes + 1
    56         bool checkInitDepth( const ast::ObjectDecl * objDecl );
     52/// True if the Initializer contains designations
     53bool isDesignated( const ast::Init * init );
    5754
    58         /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    59         /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    60         /// Currently has assertions that make it less than fully general.
    61         bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
     55/// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
     56/// type, where the depth of its type is the number of nested ArrayTypes + 1
     57bool checkInitDepth( const ast::ObjectDecl * objDecl );
    6258
    63         /// get all Ctor/Dtor call expressions from a Statement
    64         std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
     59/// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
     60/// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
     61/// Currently has assertions that make it less than fully general.
     62bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
    6563
    66         /// returns true if expr is trivially a compile-time constant
    67         bool isConstExpr( const ast::Expr * expr );
    68         bool isConstExpr( const ast::Init * init );
     64/// get all Ctor/Dtor call expressions from a Statement
     65std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    6966
    70         /// Modifies objDecl to have:
    71         ///    __attribute__((section (".data#")))
    72         /// which makes gcc put the declared variable in the data section,
    73         /// which is helpful for global constants on newer gcc versions,
    74         /// so that CFA's generated initialization won't segfault when writing it via a const cast.
    75         /// The trailing # is an injected assembly comment, to suppress the "a" in
    76         ///    .section .data,"a"
    77         ///    .section .data#,"a"
    78         /// to avoid assembler warning "ignoring changed section attributes for .data"
    79         void addDataSectionAttribute( ast::ObjectDecl * objDecl );
     67/// returns true if expr is trivially a compile-time constant
     68bool isConstExpr( const ast::Expr * expr );
     69bool isConstExpr( const ast::Init * init );
    8070
    81         class InitExpander final {
    82         public:
    83                 using IndexList = std::vector< ast::ptr< ast::Expr > >;
    84                 class ExpanderImpl;
     71/// Modifies objDecl to have:
     72///    __attribute__((section (".data#")))
     73/// which makes gcc put the declared variable in the data section,
     74/// which is helpful for global constants on newer gcc versions,
     75/// so that CFA's generated initialization won't segfault when writing it via a const cast.
     76/// The trailing # is an injected assembly comment, to suppress the "a" in
     77///    .section .data,"a"
     78///    .section .data#,"a"
     79/// to avoid assembler warning "ignoring changed section attributes for .data"
     80void addDataSectionAttribute( ast::ObjectDecl * objDecl );
    8581
    86         private:
    87                 std::shared_ptr< ExpanderImpl > expander;
    88                 std::vector< ast::ptr< ast::Expr > > crnt;
    89                 // invariant: list of size 2N (elements come in pairs [index, dimension])
    90                 IndexList indices;
     82class InitExpander final {
     83public:
     84        using IndexList = std::vector< ast::ptr< ast::Expr > >;
     85        class ExpanderImpl;
    9186
    92         public:
    93                 /// Expand by stepping through init to get each list of arguments
    94                 InitExpander( const ast::Init * init );
     87private:
     88        std::shared_ptr< ExpanderImpl > expander;
     89        std::vector< ast::ptr< ast::Expr > > crnt;
     90        // invariant: list of size 2N (elements come in pairs [index, dimension])
     91        IndexList indices;
    9592
    96                 /// Always expand to expression
    97                 InitExpander( const ast::Expr * expr );
     93public:
     94        /// Expand by stepping through init to get each list of arguments
     95        InitExpander( const ast::Init * init );
    9896
    99                 std::vector< ast::ptr< ast::Expr > > operator* ();
    100                 InitExpander & operator++ ();
     97        /// Always expand to expression
     98        InitExpander( const ast::Expr * expr );
    10199
    102                 /// builds statement which has the same semantics as a C-style list initializer (for array
    103                 /// initializers) using callExpr as the base expression to perform initialization.
    104                 /// Mutates callExpr
    105                 ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr );
     100        std::vector< ast::ptr< ast::Expr > > operator* ();
     101        InitExpander & operator++ ();
    106102
    107                 void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension );
     103        /// builds statement which has the same semantics as a C-style list initializer (for array
     104        /// initializers) using callExpr as the base expression to perform initialization.
     105        /// Mutates callExpr
     106        ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr );
    108107
    109                 void clearArrayIndices();
     108        void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension );
    110109
    111                 bool addReference();
    112         };
     110        void clearArrayIndices();
     111
     112        bool addReference();
     113};
     114
    113115} // namespace InitTweak
    114116
Note: See TracChangeset for help on using the changeset viewer.