Changeset b7b3e41 for src


Ignore:
Timestamp:
Jun 19, 2023, 1:57:11 PM (2 years ago)
Author:
caparson <caparson@…>
Branches:
master
Children:
adc73a5
Parents:
fa5e1aa5 (diff), 33d4bc8 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src
Files:
41 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Convert.cpp

    rfa5e1aa5 rb7b3e41  
    23432343                                old->location,
    23442344                                GET_ACCEPT_1(arg, Expr),
    2345                                 old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast
     2345                                old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast,
     2346                                (ast::CastExpr::CastKind) old->kind
    23462347                        )
    23472348                );
  • src/AST/Decl.cpp

    rfa5e1aa5 rb7b3e41  
    142142bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const {
    143143        if ( enumValues.empty() ) {
    144                 long long crntVal = 0;
     144                Evaluation crntVal = {0, true, true};  // until expression is given, we know to start counting from 0
    145145                for ( const Decl * member : members ) {
    146146                        const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member );
    147147                        if ( field->init ) {
    148148                                const SingleInit * init = strict_dynamic_cast< const SingleInit* >( field->init.get() );
    149                                 auto result = eval( init->value );
    150                                 if ( ! result.second ) {
     149                                crntVal = eval( init->value );
     150                                if ( ! crntVal.isEvaluableInGCC ) {
    151151                                        SemanticError( init->location, ::toString( "Non-constexpr in initialization of "
    152152                                                "enumerator: ", field ) );
    153153                                }
    154                                 crntVal = result.first;
    155154                        }
    156155                        if ( enumValues.count( field->name ) != 0 ) {
    157156                                SemanticError( location, ::toString( "Enum ", name, " has multiple members with the "   "name ", field->name ) );
    158157                        }
    159                         enumValues[ field->name ] = crntVal;
    160                         ++crntVal;
     158                        if (crntVal.hasKnownValue) {
     159                                enumValues[ field->name ] = crntVal.knownValue;
     160                        }
     161                        ++crntVal.knownValue;
    161162                }
    162163        }
  • src/AST/DeclReplacer.hpp

    rfa5e1aa5 rb7b3e41  
    1818#include <unordered_map>
    1919
    20 #include "Node.hpp"
     20namespace ast {
     21        class DeclWithType;
     22        class Expr;
     23        class Node;
     24        class TypeDecl;
     25}
    2126
    2227namespace ast {
    23         class DeclWithType;
    24         class TypeDecl;
    25         class Expr;
    2628
    27         namespace DeclReplacer {
    28                 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
    29                 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
    30                 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
     29namespace DeclReplacer {
    3130
    32                 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
    33                 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
    34                 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
    35                 const Node * replace( const Node * node, const ExprMap & exprMap);
    36         }
     31using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
     32using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
     33using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
     34
     35const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
     36const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
     37const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
     38const Node * replace( const Node * node, const ExprMap & exprMap);
     39
     40}
     41
    3742}
    3843
  • src/AST/Expr.cpp

    rfa5e1aa5 rb7b3e41  
    186186// --- CastExpr
    187187
    188 CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g )
    189 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
     188CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g, CastKind kind )
     189: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ), kind( kind ) {}
    190190
    191191bool CastExpr::get_lvalue() const {
  • src/AST/Expr.hpp

    rfa5e1aa5 rb7b3e41  
    5555                const Expr * e )
    5656        : decl( id ), declptr( declptr ), actualType( actual ), formalType( formal ), expr( e ) {}
     57
     58        operator bool() {return declptr;}
    5759};
    5860
     
    335337        GeneratedFlag isGenerated;
    336338
     339        enum CastKind {
     340                Default, // C
     341                Coerce, // reinterpret cast
     342                Return  // overload selection
     343        };
     344
     345        CastKind kind = Default;
     346
    337347        CastExpr( const CodeLocation & loc, const Expr * a, const Type * to,
    338                 GeneratedFlag g = GeneratedCast ) : Expr( loc, to ), arg( a ), isGenerated( g ) {}
     348                GeneratedFlag g = GeneratedCast, CastKind kind = Default ) : Expr( loc, to ), arg( a ), isGenerated( g ), kind( kind ) {}
    339349        /// Cast-to-void
    340         CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast );
     350        CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast, CastKind kind = Default );
    341351
    342352        /// Wrap a cast expression around an existing expression (always generated)
  • src/AST/Pass.hpp

    rfa5e1aa5 rb7b3e41  
    414414};
    415415
    416 /// Use when the templated visitor should update the symbol table
     416/// Use when the templated visitor should update the symbol table,
     417/// that is, when your pass core needs to query the symbol table.
     418/// Expected setups:
     419/// - For master passes that kick off at the compilation unit
     420///   - before resolver: extend WithSymbolTableX<IgnoreErrors>
     421///   - after resolver: extend WithSymbolTable and use defaults
     422///   - (FYI, for completeness, the resolver's main pass uses ValidateOnAdd when it kicks off)
     423/// - For helper passes that kick off at arbitrary points in the AST:
     424///   - take an existing symbol table as a parameter, extend WithSymbolTable,
     425///     and construct with WithSymbolTable(const SymbolTable &)
    417426struct WithSymbolTable {
    418         SymbolTable symtab;
     427        WithSymbolTable(const ast::SymbolTable & from) : symtab(from) {}
     428        WithSymbolTable(ast::SymbolTable::ErrorDetection errorMode = ast::SymbolTable::ErrorDetection::AssertClean) : symtab(errorMode) {}
     429        ast::SymbolTable symtab;
     430};
     431template <ast::SymbolTable::ErrorDetection errorMode>
     432struct WithSymbolTableX : WithSymbolTable {
     433        WithSymbolTableX() : WithSymbolTable(errorMode) {}
    419434};
    420435
  • src/AST/Pass.impl.hpp

    rfa5e1aa5 rb7b3e41  
    7272                template<typename it_t, template <class...> class container_t>
    7373                static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
    74                         if(empty(decls)) return;
     74                        if ( empty( decls ) ) return;
    7575
    7676                        std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
     
    7878                                });
    7979                        decls->clear();
    80                         if(mutated) *mutated = true;
     80                        if ( mutated ) *mutated = true;
    8181                }
    8282
    8383                template<typename it_t, template <class...> class container_t>
    8484                static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) {
    85                         if(empty(stmts)) return;
     85                        if ( empty( stmts ) ) return;
    8686
    8787                        std::move(stmts->begin(), stmts->end(), it);
    8888                        stmts->clear();
    89                         if(mutated) *mutated = true;
     89                        if ( mutated ) *mutated = true;
    9090                }
    9191
     
    9393                /// Check if should be skipped, different for pointers and containers
    9494                template<typename node_t>
    95                 bool skip( const ast::ptr<node_t> & val) {
     95                bool skip( const ast::ptr<node_t> & val ) {
    9696                        return !val;
    9797                }
     
    110110
    111111                template<typename node_t>
    112                 const node_t & get( const node_t & val, long) {
     112                const node_t & get( const node_t & val, long ) {
    113113                        return val;
    114114                }
     
    126126                }
    127127        }
    128 
    129         template< typename core_t >
    130         template< typename node_t >
    131         auto ast::Pass< core_t >::call_accept( const node_t * node )
    132                 -> typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
    133         {
    134                 __pedantic_pass_assert( __visit_children() );
    135                 __pedantic_pass_assert( node );
    136 
    137                 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
    138                 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
    139 
    140                 auto nval = node->accept( *this );
    141                 __pass::result1<
    142                         typename std::remove_pointer< decltype( node->accept(*this) ) >::type
    143                 > res;
    144                 res.differs = nval != node;
    145                 res.value = nval;
    146                 return res;
    147         }
    148 
    149         template< typename core_t >
    150         __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    151                 __pedantic_pass_assert( __visit_children() );
    152                 __pedantic_pass_assert( expr );
    153 
    154                 auto nval = expr->accept( *this );
    155                 return { nval != expr, nval };
    156         }
    157 
    158         template< typename core_t >
    159         __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    160                 __pedantic_pass_assert( __visit_children() );
    161                 __pedantic_pass_assert( stmt );
    162 
    163                 const ast::Stmt * nval = stmt->accept( *this );
    164                 return { nval != stmt, nval };
    165         }
    166 
    167         template< typename core_t >
    168         __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) {
    169                 __pedantic_pass_assert( __visit_children() );
    170                 __pedantic_pass_assert( expr );
    171 
    172                 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
    173                 if ( typeSubs_ptr && expr->env ) {
    174                         *typeSubs_ptr = expr->env;
    175                 }
    176 
    177                 auto nval = expr->accept( *this );
    178                 return { nval != expr, nval };
    179         }
    180 
    181         template< typename core_t >
    182         __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
    183                 __pedantic_pass_assert( __visit_children() );
    184                 __pedantic_pass_assert( stmt );
    185 
    186                 // add a few useful symbols to the scope
    187                 using __pass::empty;
    188 
    189                 // get the stmts/decls that will need to be spliced in
    190                 auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
    191                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
    192                 auto decls_before = __pass::declsToAddBefore( core, 0 );
    193                 auto decls_after  = __pass::declsToAddAfter ( core, 0 );
    194 
    195                 // These may be modified by subnode but most be restored once we exit this statemnet.
    196                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::typeSubs( core, 0 ) );
    197                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    198                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
    199                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
    200                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
    201 
    202                 // Now is the time to actually visit the node
    203                 const ast::Stmt * nstmt = stmt->accept( *this );
    204 
    205                 // If the pass doesn't want to add anything then we are done
    206                 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
    207                         return { nstmt != stmt, nstmt };
    208                 }
    209 
    210                 // Make sure that it is either adding statements or declartions but not both
    211                 // this is because otherwise the order would be awkward to predict
    212                 assert(( empty( stmts_before ) && empty( stmts_after ))
    213                     || ( empty( decls_before ) && empty( decls_after )) );
    214 
    215                 // Create a new Compound Statement to hold the new decls/stmts
    216                 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
    217 
    218                 // Take all the declarations that go before
    219                 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
    220                 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
    221 
    222                 // Insert the original declaration
    223                 compound->kids.emplace_back( nstmt );
    224 
    225                 // Insert all the declarations that go before
    226                 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
    227                 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
    228 
    229                 return {true, compound};
    230         }
    231 
    232         template< typename core_t >
    233         template< template <class...> class container_t >
    234         __pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    235                 __pedantic_pass_assert( __visit_children() );
    236                 if( statements.empty() ) return {};
    237 
    238                 // We are going to aggregate errors for all these statements
    239                 SemanticErrorException errors;
    240 
    241                 // add a few useful symbols to the scope
    242                 using __pass::empty;
    243 
    244                 // get the stmts/decls that will need to be spliced in
    245                 auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
    246                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
    247                 auto decls_before = __pass::declsToAddBefore( core, 0 );
    248                 auto decls_after  = __pass::declsToAddAfter ( core, 0 );
    249 
    250                 // These may be modified by subnode but most be restored once we exit this statemnet.
    251                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    252                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
    253                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
    254                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
    255 
    256                 // update pass statitistics
    257                 pass_visitor_stats.depth++;
    258                 pass_visitor_stats.max->push(pass_visitor_stats.depth);
    259                 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    260 
    261                 __pass::resultNstmt<container_t> new_kids;
    262                 for( auto value : enumerate( statements ) ) {
    263                         try {
    264                                 size_t i = value.idx;
    265                                 const Stmt * stmt = value.val;
    266                                 __pedantic_pass_assert( stmt );
    267                                 const ast::Stmt * new_stmt = stmt->accept( *this );
    268                                 assert( new_stmt );
    269                                 if(new_stmt != stmt ) { new_kids.differs = true; }
    270 
    271                                 // Make sure that it is either adding statements or declartions but not both
    272                                 // this is because otherwise the order would be awkward to predict
    273                                 assert(( empty( stmts_before ) && empty( stmts_after ))
    274                                     || ( empty( decls_before ) && empty( decls_after )) );
    275 
    276                                 // Take all the statements which should have gone after, N/A for first iteration
    277                                 new_kids.take_all( decls_before );
    278                                 new_kids.take_all( stmts_before );
    279 
    280                                 // Now add the statement if there is one
    281                                 if(new_stmt != stmt) {
    282                                         new_kids.values.emplace_back( new_stmt, i, false );
    283                                 } else {
    284                                         new_kids.values.emplace_back( nullptr, i, true );
    285                                 }
    286 
    287                                 // Take all the declarations that go before
    288                                 new_kids.take_all( decls_after );
    289                                 new_kids.take_all( stmts_after );
     128}
     129
     130template< typename core_t >
     131template< typename node_t >
     132auto ast::Pass< core_t >::call_accept( const node_t * node ) ->
     133        typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
     134{
     135        __pedantic_pass_assert( __visit_children() );
     136        __pedantic_pass_assert( node );
     137
     138        static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" );
     139        static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" );
     140
     141        auto nval = node->accept( *this );
     142        __pass::result1<
     143                typename std::remove_pointer< decltype( node->accept(*this) ) >::type
     144        > res;
     145        res.differs = nval != node;
     146        res.value = nval;
     147        return res;
     148}
     149
     150template< typename core_t >
     151ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
     152        __pedantic_pass_assert( __visit_children() );
     153        __pedantic_pass_assert( expr );
     154
     155        auto nval = expr->accept( *this );
     156        return { nval != expr, nval };
     157}
     158
     159template< typename core_t >
     160ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
     161        __pedantic_pass_assert( __visit_children() );
     162        __pedantic_pass_assert( stmt );
     163
     164        const ast::Stmt * nval = stmt->accept( *this );
     165        return { nval != stmt, nval };
     166}
     167
     168template< typename core_t >
     169ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) {
     170        __pedantic_pass_assert( __visit_children() );
     171        __pedantic_pass_assert( expr );
     172
     173        const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
     174        if ( typeSubs_ptr && expr->env ) {
     175                *typeSubs_ptr = expr->env;
     176        }
     177
     178        auto nval = expr->accept( *this );
     179        return { nval != expr, nval };
     180}
     181
     182template< typename core_t >
     183ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
     184        __pedantic_pass_assert( __visit_children() );
     185        __pedantic_pass_assert( stmt );
     186
     187        // add a few useful symbols to the scope
     188        using __pass::empty;
     189
     190        // get the stmts/decls that will need to be spliced in
     191        auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
     192        auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
     193        auto decls_before = __pass::declsToAddBefore( core, 0 );
     194        auto decls_after  = __pass::declsToAddAfter ( core, 0 );
     195
     196        // These may be modified by subnode but most be restored once we exit this statemnet.
     197        ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::typeSubs( core, 0 ) );
     198        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
     199        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     200        ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
     201        ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
     202
     203        // Now is the time to actually visit the node
     204        const ast::Stmt * nstmt = stmt->accept( *this );
     205
     206        // If the pass doesn't want to add anything then we are done
     207        if ( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
     208                return { nstmt != stmt, nstmt };
     209        }
     210
     211        // Make sure that it is either adding statements or declartions but not both
     212        // this is because otherwise the order would be awkward to predict
     213        assert(( empty( stmts_before ) && empty( stmts_after ))
     214            || ( empty( decls_before ) && empty( decls_after )) );
     215
     216        // Create a new Compound Statement to hold the new decls/stmts
     217        ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
     218
     219        // Take all the declarations that go before
     220        __pass::take_all( std::back_inserter( compound->kids ), decls_before );
     221        __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
     222
     223        // Insert the original declaration
     224        compound->kids.emplace_back( nstmt );
     225
     226        // Insert all the declarations that go before
     227        __pass::take_all( std::back_inserter( compound->kids ), decls_after );
     228        __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
     229
     230        return { true, compound };
     231}
     232
     233template< typename core_t >
     234template< template <class...> class container_t >
     235ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     236        __pedantic_pass_assert( __visit_children() );
     237        if ( statements.empty() ) return {};
     238
     239        // We are going to aggregate errors for all these statements
     240        SemanticErrorException errors;
     241
     242        // add a few useful symbols to the scope
     243        using __pass::empty;
     244
     245        // get the stmts/decls that will need to be spliced in
     246        auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
     247        auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
     248        auto decls_before = __pass::declsToAddBefore( core, 0 );
     249        auto decls_after  = __pass::declsToAddAfter ( core, 0 );
     250
     251        // These may be modified by subnode but most be restored once we exit this statemnet.
     252        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
     253        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     254        ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
     255        ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
     256
     257        // update pass statitistics
     258        pass_visitor_stats.depth++;
     259        pass_visitor_stats.max->push(pass_visitor_stats.depth);
     260        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
     261
     262        __pass::resultNstmt<container_t> new_kids;
     263        for ( auto value : enumerate( statements ) ) {
     264                try {
     265                        size_t i = value.idx;
     266                        const Stmt * stmt = value.val;
     267                        __pedantic_pass_assert( stmt );
     268                        const ast::Stmt * new_stmt = stmt->accept( *this );
     269                        assert( new_stmt );
     270                        if ( new_stmt != stmt ) { new_kids.differs = true; }
     271
     272                        // Make sure that it is either adding statements or declartions but not both
     273                        // this is because otherwise the order would be awkward to predict
     274                        assert(( empty( stmts_before ) && empty( stmts_after ))
     275                            || ( empty( decls_before ) && empty( decls_after )) );
     276
     277                        // Take all the statements which should have gone after, N/A for first iteration
     278                        new_kids.take_all( decls_before );
     279                        new_kids.take_all( stmts_before );
     280
     281                        // Now add the statement if there is one
     282                        if ( new_stmt != stmt ) {
     283                                new_kids.values.emplace_back( new_stmt, i, false );
     284                        } else {
     285                                new_kids.values.emplace_back( nullptr, i, true );
    290286                        }
    291                         catch ( SemanticErrorException &e ) {
    292                                 errors.append( e );
     287
     288                        // Take all the declarations that go before
     289                        new_kids.take_all( decls_after );
     290                        new_kids.take_all( stmts_after );
     291                } catch ( SemanticErrorException &e ) {
     292                        errors.append( e );
     293                }
     294        }
     295        pass_visitor_stats.depth--;
     296        if ( !errors.isEmpty() ) { throw errors; }
     297
     298        return new_kids;
     299}
     300
     301template< typename core_t >
     302template< template <class...> class container_t, typename node_t >
     303ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     304        __pedantic_pass_assert( __visit_children() );
     305        if ( container.empty() ) return {};
     306        SemanticErrorException errors;
     307
     308        pass_visitor_stats.depth++;
     309        pass_visitor_stats.max->push(pass_visitor_stats.depth);
     310        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
     311
     312        bool mutated = false;
     313        container_t<ptr<node_t>> new_kids;
     314        for ( const node_t * node : container ) {
     315                try {
     316                        __pedantic_pass_assert( node );
     317                        const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
     318                        if ( new_stmt != node ) {
     319                                mutated = true;
     320                                new_kids.emplace_back( new_stmt );
     321                        } else {
     322                                new_kids.emplace_back( nullptr );
    293323                        }
    294                 }
    295                 pass_visitor_stats.depth--;
    296                 if ( !errors.isEmpty() ) { throw errors; }
    297 
    298                 return new_kids;
    299         }
    300 
    301         template< typename core_t >
    302         template< template <class...> class container_t, typename node_t >
    303         __pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    304                 __pedantic_pass_assert( __visit_children() );
    305                 if( container.empty() ) return {};
    306                 SemanticErrorException errors;
    307 
    308                 pass_visitor_stats.depth++;
    309                 pass_visitor_stats.max->push(pass_visitor_stats.depth);
    310                 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    311 
    312                 bool mutated = false;
    313                 container_t<ptr<node_t>> new_kids;
    314                 for ( const node_t * node : container ) {
    315                         try {
    316                                 __pedantic_pass_assert( node );
    317                                 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
    318                                 if(new_stmt != node ) {
    319                                         mutated = true;
    320                                         new_kids.emplace_back( new_stmt );
    321                                 } else {
    322                                         new_kids.emplace_back( nullptr );
    323                                 }
    324 
    325                         }
    326                         catch( SemanticErrorException &e ) {
    327                                 errors.append( e );
    328                         }
    329                 }
    330 
    331                 __pedantic_pass_assert( new_kids.size() == container.size() );
    332                 pass_visitor_stats.depth--;
    333                 if ( ! errors.isEmpty() ) { throw errors; }
    334 
    335                 return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids };
    336         }
    337 
    338         template< typename core_t >
    339         template<typename node_t, typename super_t, typename field_t>
    340         void ast::Pass< core_t >::maybe_accept(
    341                 const node_t * & parent,
    342                 field_t super_t::*field
    343         ) {
    344                 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
    345 
    346                 if(__pass::skip(parent->*field)) return;
    347                 const auto & old_val = __pass::get(parent->*field, 0);
    348 
    349                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    350 
    351                 auto new_val = call_accept( old_val );
    352 
    353                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
    354 
    355                 if( new_val.differs ) {
    356                         auto new_parent = __pass::mutate<core_t>(parent);
    357                         new_val.apply(new_parent, field);
    358                         parent = new_parent;
    359                 }
    360         }
    361 
    362         template< typename core_t >
    363         template<typename node_t, typename super_t, typename field_t>
    364         void ast::Pass< core_t >::maybe_accept_top(
    365                 const node_t * & parent,
    366                 field_t super_t::*field
    367         ) {
    368                 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
    369 
    370                 if(__pass::skip(parent->*field)) return;
    371                 const auto & old_val = __pass::get(parent->*field, 0);
    372 
    373                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    374 
    375                 auto new_val = call_accept_top( old_val );
    376 
    377                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
    378 
    379                 if( new_val.differs ) {
    380                         auto new_parent = __pass::mutate<core_t>(parent);
    381                         new_val.apply(new_parent, field);
    382                         parent = new_parent;
    383                 }
    384         }
    385 
    386         template< typename core_t >
    387         template<typename node_t, typename super_t, typename field_t>
    388         void ast::Pass< core_t >::maybe_accept_as_compound(
    389                 const node_t * & parent,
    390                 field_t super_t::*child
    391         ) {
    392                 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
    393 
    394                 if(__pass::skip(parent->*child)) return;
    395                 const auto & old_val = __pass::get(parent->*child, 0);
    396 
    397                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    398 
    399                 auto new_val = call_accept_as_compound( old_val );
    400 
    401                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
    402 
    403                 if( new_val.differs ) {
    404                         auto new_parent = __pass::mutate<core_t>(parent);
    405                         new_val.apply( new_parent, child );
    406                         parent = new_parent;
    407                 }
    408         }
    409 
     324                } catch ( SemanticErrorException &e ) {
     325                        errors.append( e );
     326                }
     327        }
     328
     329        __pedantic_pass_assert( new_kids.size() == container.size() );
     330        pass_visitor_stats.depth--;
     331        if ( !errors.isEmpty() ) { throw errors; }
     332
     333        return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids };
     334}
     335
     336template< typename core_t >
     337template<typename node_t, typename super_t, typename field_t>
     338void ast::Pass< core_t >::maybe_accept(
     339        const node_t * & parent,
     340        field_t super_t::*field
     341) {
     342        static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
     343
     344        if ( __pass::skip( parent->*field ) ) return;
     345        const auto & old_val = __pass::get(parent->*field, 0);
     346
     347        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
     348
     349        auto new_val = call_accept( old_val );
     350
     351        static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
     352
     353        if ( new_val.differs ) {
     354                auto new_parent = __pass::mutate<core_t>(parent);
     355                new_val.apply(new_parent, field);
     356                parent = new_parent;
     357        }
     358}
     359
     360template< typename core_t >
     361template<typename node_t, typename super_t, typename field_t>
     362void ast::Pass< core_t >::maybe_accept_top(
     363        const node_t * & parent,
     364        field_t super_t::*field
     365) {
     366        static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
     367
     368        if ( __pass::skip( parent->*field ) ) return;
     369        const auto & old_val = __pass::get(parent->*field, 0);
     370
     371        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
     372
     373        auto new_val = call_accept_top( old_val );
     374
     375        static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
     376
     377        if ( new_val.differs ) {
     378                auto new_parent = __pass::mutate<core_t>(parent);
     379                new_val.apply(new_parent, field);
     380                parent = new_parent;
     381        }
     382}
     383
     384template< typename core_t >
     385template<typename node_t, typename super_t, typename field_t>
     386void ast::Pass< core_t >::maybe_accept_as_compound(
     387        const node_t * & parent,
     388        field_t super_t::*child
     389) {
     390        static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
     391
     392        if ( __pass::skip( parent->*child ) ) return;
     393        const auto & old_val = __pass::get(parent->*child, 0);
     394
     395        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
     396
     397        auto new_val = call_accept_as_compound( old_val );
     398
     399        static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" );
     400
     401        if ( new_val.differs ) {
     402                auto new_parent = __pass::mutate<core_t>(parent);
     403                new_val.apply( new_parent, child );
     404                parent = new_parent;
     405        }
    410406}
    411407
     
    761757
    762758        if ( __visit_children() ) {
    763                 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
    764                 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
    765                         if ( enterScope ) {
    766                                 __pass::symtab::enter(core, 0);
    767                         }
    768                 }, [this, leaveScope = !this->atFunctionTop]() {
    769                         if ( leaveScope ) {
    770                                 __pass::symtab::leave(core, 0);
    771                         }
    772                 });
    773                 ValueGuard< bool > guard2( atFunctionTop );
    774                 atFunctionTop = false;
    775                 guard_scope guard3 { *this };
    776                 maybe_accept( node, &CompoundStmt::kids );
     759                // Do not enter (or leave) a new symbol table scope if atFunctionTop.
     760                // But always enter (and leave) a new general scope.
     761                if ( atFunctionTop ) {
     762                        ValueGuard< bool > guard1( atFunctionTop );
     763                        atFunctionTop = false;
     764                        guard_scope guard2( *this );
     765                        maybe_accept( node, &CompoundStmt::kids );
     766                } else {
     767                        guard_symtab guard1( *this );
     768                        guard_scope guard2( *this );
     769                        maybe_accept( node, &CompoundStmt::kids );
     770                }
    777771        }
    778772
  • src/AST/SymbolTable.cpp

    rfa5e1aa5 rb7b3e41  
    1919
    2020#include "Copy.hpp"
     21#include <iostream>
     22#include <algorithm>
     23
    2124#include "Decl.hpp"
    2225#include "Expr.hpp"
     
    8891}
    8992
    90 SymbolTable::SymbolTable()
     93SymbolTable::SymbolTable( ErrorDetection errorMode )
    9194: idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
    92   prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
     95  prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; }
    9396
    9497SymbolTable::~SymbolTable() { stats().size->push( idTable ? idTable->size() : 0 ); }
     98
     99void SymbolTable::OnFindError( CodeLocation location, std::string error ) const {
     100        assertf( errorMode != AssertClean, "Name collision/redefinition, found during a compilation phase where none should be possible.  Detail: %s", error.c_str() );
     101        if (errorMode == ValidateOnAdd) {
     102                SemanticError(location, error);
     103        }
     104        assertf( errorMode == IgnoreErrors, "Unrecognized symbol-table error mode %d", errorMode );
     105}
    95106
    96107void SymbolTable::enterScope() {
     
    195206                        out.push_back(decl.second);
    196207                }
     208
     209                // std::cerr << otypeKey << ' ' << out.size() << std::endl;
    197210        }
    198211
     
    269282}
    270283
    271 namespace {
    272         /// true if redeclaration conflict between two types
    273         bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) {
    274                 if ( existing->base == nullptr ) {
    275                         return false;
    276                 } else if ( added->base == nullptr ) {
    277                         return true;
    278                 } else {
    279                         // typedef redeclarations are errors only if types are different
    280                         if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) {
    281                                 SemanticError( added->location, "redeclaration of " + added->name );
    282                         }
    283                 }
    284                 // does not need to be added to the table if both existing and added have a base that are
    285                 // the same
     284bool SymbolTable::addedTypeConflicts(
     285                const NamedTypeDecl * existing, const NamedTypeDecl * added ) const {
     286        if ( existing->base == nullptr ) {
     287                return false;
     288        } else if ( added->base == nullptr ) {
    286289                return true;
    287         }
    288 
    289         /// true if redeclaration conflict between two aggregate declarations
    290         bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) {
    291                 if ( ! existing->body ) {
    292                         return false;
    293                 } else if ( added->body ) {
    294                         SemanticError( added, "redeclaration of " );
    295                 }
    296                 return true;
    297         }
     290        } else {
     291                // typedef redeclarations are errors only if types are different
     292                if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) {
     293                        OnFindError( added->location, "redeclaration of " + added->name );
     294                }
     295        }
     296        // does not need to be added to the table if both existing and added have a base that are
     297        // the same
     298        return true;
     299}
     300
     301bool SymbolTable::addedDeclConflicts(
     302                const AggregateDecl * existing, const AggregateDecl * added ) const {
     303        if ( ! existing->body ) {
     304                return false;
     305        } else if ( added->body ) {
     306                OnFindError( added, "redeclaration of " );
     307        }
     308        return true;
    298309}
    299310
     
    648659                if ( deleter && ! existing.deleter ) {
    649660                        if ( handleConflicts.mode == OnConflict::Error ) {
    650                                 SemanticError( added, "deletion of defined identifier " );
     661                                OnFindError( added, "deletion of defined identifier " );
    651662                        }
    652663                        return true;
    653664                } else if ( ! deleter && existing.deleter ) {
    654665                        if ( handleConflicts.mode == OnConflict::Error ) {
    655                                 SemanticError( added, "definition of deleted identifier " );
     666                                OnFindError( added, "definition of deleted identifier " );
    656667                        }
    657668                        return true;
     
    661672                if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    662673                        if ( handleConflicts.mode == OnConflict::Error ) {
    663                                 SemanticError( added,
     674                                OnFindError( added,
    664675                                        isFunction( added ) ?
    665676                                                "duplicate function definition for " :
     
    670681        } else {
    671682                if ( handleConflicts.mode == OnConflict::Error ) {
    672                         SemanticError( added, "duplicate definition for " );
     683                        OnFindError( added, "duplicate definition for " );
    673684                }
    674685                return true;
     
    722733                // Check that a Cforall declaration doesn't override any C declaration
    723734                if ( hasCompatibleCDecl( name, mangleName ) ) {
    724                         SemanticError( decl, "Cforall declaration hides C function " );
     735                        OnFindError( decl, "Cforall declaration hides C function " );
    725736                }
    726737        } else {
     
    728739                // type-compatibility, which it may not be.
    729740                if ( hasIncompatibleCDecl( name, mangleName ) ) {
    730                         SemanticError( decl, "conflicting overload of C function " );
     741                        OnFindError( decl, "conflicting overload of C function " );
    731742                }
    732743        }
  • src/AST/SymbolTable.hpp

    rfa5e1aa5 rb7b3e41  
    9393
    9494public:
    95         SymbolTable();
     95
     96        /// Mode to control when (during which pass) user-caused name-declaration errors get reported.
     97        /// The default setting `AssertClean` supports, "I expect all user-caused errors to have been
     98        /// reported by now," or, "I wouldn't know what to do with an error; are there even any here?"
     99        enum ErrorDetection {
     100                AssertClean,               ///< invalid user decls => assert fails during addFoo (default)
     101                ValidateOnAdd,             ///< invalid user decls => calls SemanticError during addFoo
     102                IgnoreErrors               ///< acts as if unspecified decls were removed, forcing validity
     103        };
     104
     105        explicit SymbolTable(
     106                ErrorDetection             ///< mode for the lifetime of the symbol table (whole pass)
     107        );
     108        SymbolTable() : SymbolTable(AssertClean) {}
    96109        ~SymbolTable();
     110
     111        ErrorDetection getErrorMode() const {
     112                return errorMode;
     113        }
    97114
    98115        // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
     
    158175
    159176private:
     177        void OnFindError( CodeLocation location, std::string error ) const;
     178
     179        template< typename T >
     180        void OnFindError( const T * obj, const std::string & error ) const {
     181                OnFindError( obj->location, toString( error, obj ) );
     182        }
     183
     184        template< typename T >
     185        void OnFindError( CodeLocation location, const T * obj, const std::string & error ) const {
     186                OnFindError( location, toString( error, obj ) );
     187        }
     188
    160189        /// Ensures that a proper backtracking scope exists before a mutation
    161190        void lazyInitScope();
     
    168197        bool removeSpecialOverrides( IdData & decl, MangleTable::Ptr & mangleTable );
    169198
    170         /// Options for handling identifier conflicts
     199        /// Error detection mode given at construction (pass-specific).
     200        /// Logically const, except that the symbol table's push-pop is achieved by autogenerated
     201        /// assignment onto self.  The feield is left motuable to keep this code-gen simple.
     202        /// Conceptual constness is preserved by all SymbolTable in a stack sharing the same mode.
     203        ErrorDetection errorMode;
     204
     205        /// Options for handling identifier conflicts.
     206        /// Varies according to AST location during traversal: captures semantics of the construct
     207        /// being visited as "would shadow" vs "must not collide."
     208        /// At a given AST location, is the same for every pass.
    171209        struct OnConflict {
    172210                enum {
    173                         Error,  ///< Throw a semantic error
     211                        Error,  ///< Follow the current pass's ErrorDetection mode (may throw a semantic error)
    174212                        Delete  ///< Delete the earlier version with the delete statement
    175213                } mode;
     
    191229                const Decl * deleter );
    192230
     231        /// true if redeclaration conflict between two types
     232        bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) const;
     233
     234        /// true if redeclaration conflict between two aggregate declarations
     235        bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) const;
     236
    193237        /// common code for addId, addDeletedId, etc.
    194238        void addIdCommon(
     
    213257}
    214258
     259
    215260// Local Variables: //
    216261// tab-width: 4 //
  • src/AST/Type.hpp

    rfa5e1aa5 rb7b3e41  
    451451        bool operator==(const TypeEnvKey & other) const;
    452452        bool operator<(const TypeEnvKey & other) const;
    453 };
     453        operator bool() {return base;}
     454};
     455
    454456
    455457/// tuple type e.g. `[int, char]`
  • src/AST/TypeEnvironment.cpp

    rfa5e1aa5 rb7b3e41  
    135135                }
    136136        }
    137         sub.normalize();
     137        // sub.normalize();
    138138}
    139139
  • src/AST/TypeEnvironment.hpp

    rfa5e1aa5 rb7b3e41  
    6363
    6464                int cmp = d1->var->name.compare( d2->var->name );
    65                 return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
     65                return cmp > 0 || ( cmp == 0 && d1->result < d2->result );
    6666        }
    6767};
  • src/AST/Util.cpp

    rfa5e1aa5 rb7b3e41  
    8383}
    8484
     85/// Check that the MemberExpr has an aggregate type and matching member.
     86void memberMatchesAggregate( const MemberExpr * expr ) {
     87        const Type * aggrType = expr->aggregate->result->stripReferences();
     88        const AggregateDecl * decl = nullptr;
     89        if ( auto inst = dynamic_cast<const StructInstType *>( aggrType ) ) {
     90                decl = inst->base;
     91        } else if ( auto inst = dynamic_cast<const UnionInstType *>( aggrType ) ) {
     92                decl = inst->base;
     93        }
     94        assertf( decl, "Aggregate of member not correct type." );
     95
     96        for ( auto aggrMember : decl->members ) {
     97                if ( expr->member == aggrMember ) {
     98                        return;
     99                }
     100        }
     101        assertf( false, "Member not found." );
     102}
     103
    85104struct InvariantCore {
    86105        // To save on the number of visits: this is a kind of composed core.
     
    108127        }
    109128
     129        void previsit( const MemberExpr * node ) {
     130                previsit( (const ParseNode *)node );
     131                memberMatchesAggregate( node );
     132        }
     133
    110134        void postvisit( const Node * node ) {
    111135                no_strong_cycles.postvisit( node );
  • src/Common/Eval.cc

    rfa5e1aa5 rb7b3e41  
    9696// New AST
    9797struct EvalNew : public ast::WithShortCircuiting {
    98         long long int value = 0;                                                        // compose the result of the constant expression
    99         bool valid = true;                                                                      // true => constant expression and value is the result
    100                                                                                                                 // false => not constant expression, e.g., ++i
    101         bool cfavalid = true;                                                           // true => constant expression and value computable
    102                                                                                                                 // false => constant expression but value not computable, e.g., sizeof(int)
     98        Evaluation result = { 0, true, true };
    10399
    104100        void previsit( const ast::Node * ) { visit_children = false; }
    105         void postvisit( const ast::Node * ) { cfavalid = valid = false; }
     101        void postvisit( const ast::Node * ) { result.isEvaluableInGCC = result.hasKnownValue = false; }
    106102
    107103        void postvisit( const ast::UntypedExpr * ) {
     
    110106
    111107        void postvisit( const ast::ConstantExpr * expr ) {      // only handle int constants
    112                 value = expr->intValue();
     108                result.knownValue = expr->intValue();
     109                result.hasKnownValue = true;
     110                result.isEvaluableInGCC = true;
    113111        }
    114112
    115113        void postvisit( const ast::SizeofExpr * ) {
    116                 // do not change valid or value => let C figure it out
    117                 cfavalid = false;
     114                result.hasKnownValue = false;
     115                result.isEvaluableInGCC = true;
    118116        }
    119117
    120118        void postvisit( const ast::AlignofExpr * ) {
    121                 // do not change valid or value => let C figure it out
    122                 cfavalid = false;
     119                result.hasKnownValue = false;
     120                result.isEvaluableInGCC = true;
    123121        }
    124122
    125123        void postvisit( const ast::OffsetofExpr * ) {
    126                 // do not change valid or value => let C figure it out
    127                 cfavalid = false;
     124                result.hasKnownValue = false;
     125                result.isEvaluableInGCC = true;
    128126        }
    129127
    130128        void postvisit( const ast::LogicalExpr * expr ) {
    131                 std::pair<long long int, bool> arg1, arg2;
     129                Evaluation arg1, arg2;
    132130                arg1 = eval( expr->arg1 );
    133                 valid &= arg1.second;
    134                 if ( ! valid ) return;
     131                result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
     132                if ( ! result.isEvaluableInGCC ) return;
    135133                arg2 = eval( expr->arg2 );
    136                 valid &= arg2.second;
    137                 if ( ! valid ) return;
     134                result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
     135                if ( ! result.isEvaluableInGCC ) return;
     136
     137                result.hasKnownValue &= arg1.hasKnownValue;
     138                result.hasKnownValue &= arg2.hasKnownValue;
     139                if ( ! result.hasKnownValue ) return;
    138140
    139141                if ( expr->isAnd ) {
    140                         value = arg1.first && arg2.first;
     142                        result.knownValue = arg1.knownValue && arg2.knownValue;
    141143                } else {
    142                         value = arg1.first || arg2.first;
     144                        result.knownValue = arg1.knownValue || arg2.knownValue;
    143145                } // if
    144146        }
    145147
    146148        void postvisit( const ast::ConditionalExpr * expr ) {
    147                 std::pair<long long int, bool> arg1, arg2, arg3;
     149                Evaluation arg1, arg2, arg3;
    148150                arg1 = eval( expr->arg1 );
    149                 valid &= arg1.second;
    150                 if ( ! valid ) return;
     151                result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
     152                if ( ! result.isEvaluableInGCC ) return;
    151153                arg2 = eval( expr->arg2 );
    152                 valid &= arg2.second;
    153                 if ( ! valid ) return;
     154                result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
     155                if ( ! result.isEvaluableInGCC ) return;
    154156                arg3 = eval( expr->arg3 );
    155                 valid &= arg3.second;
    156                 if ( ! valid ) return;
    157 
    158                 value = arg1.first ? arg2.first : arg3.first;
     157                result.isEvaluableInGCC &= arg3.isEvaluableInGCC;
     158                if ( ! result.isEvaluableInGCC ) return;
     159
     160                result.hasKnownValue &= arg1.hasKnownValue;
     161                result.hasKnownValue &= arg2.hasKnownValue;
     162                result.hasKnownValue &= arg3.hasKnownValue;
     163                if ( ! result.hasKnownValue ) return;
     164
     165                result.knownValue = arg1.knownValue ? arg2.knownValue : arg3.knownValue;
    159166        }
    160167
    161168        void postvisit( const ast::CastExpr * expr ) {         
    162                 // cfa-cc generates a cast before every constant and many other places, e.g., (int)3, so the cast argument must
    163                 // be evaluated to get the constant value.
    164                 auto arg = eval(expr->arg);
    165                 valid = arg.second;
    166                 value = arg.first;
    167                 cfavalid = false;
     169                // cfa-cc generates a cast before every constant and many other places, e.g., (int)3,
     170                // so we must use the value from the cast argument, even though we lack any basis for evaluating wraparound effects, etc
     171                result = eval(expr->arg);
    168172        }
    169173
    170174        void postvisit( const ast::VariableExpr * expr ) {
     175                result.hasKnownValue = false;
     176                result.isEvaluableInGCC = false;
    171177                if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
    172178                        if ( const ast::EnumDecl * decl = inst->base ) {
    173                                 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
    174                                         return;
    175                                 }
     179                                result.isEvaluableInGCC = true;
     180                                result.hasKnownValue = decl->valueOf( expr->var, result.knownValue ); // result.knownValue filled by valueOf
    176181                        }
    177182                }
    178                 valid = false;
    179183        }
    180184
    181185        void postvisit( const ast::ApplicationExpr * expr ) {
    182186                const ast::DeclWithType * function = ast::getFunction(expr);
    183                 if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; }
     187                if ( ! function || function->linkage != ast::Linkage::Intrinsic ) {
     188                        result.isEvaluableInGCC = false;
     189                        result.hasKnownValue = false;
     190                        return;
     191                }
    184192                const std::string & fname = function->name;
    185193                assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
     
    187195                if ( expr->args.size() == 1 ) {
    188196                        // pre/postfix operators ++ and -- => assignment, which is not constant
    189                         std::pair<long long int, bool> arg1;
     197                        Evaluation arg1;
    190198                        arg1 = eval(expr->args.front());
    191                         valid &= arg1.second;
    192                         if ( ! valid ) return;
     199                        result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
     200                        if ( ! result.isEvaluableInGCC ) return;
     201
     202                        result.hasKnownValue &= arg1.hasKnownValue;
     203                        if ( ! result.hasKnownValue ) return;
    193204
    194205                        if (fname == "+?") {
    195                                 value = arg1.first;
     206                                result.knownValue = arg1.knownValue;
    196207                        } else if (fname == "-?") {
    197                                 value = -arg1.first;
     208                                result.knownValue = -arg1.knownValue;
    198209                        } else if (fname == "~?") {
    199                                 value = ~arg1.first;
     210                                result.knownValue = ~arg1.knownValue;
    200211                        } else if (fname == "!?") {
    201                                 value = ! arg1.first;
     212                                result.knownValue = ! arg1.knownValue;
    202213                        } else {
    203                                 valid = false;
     214                                result.isEvaluableInGCC = false;
     215                                result.hasKnownValue = false;
    204216                        } // if
    205217                } else { // => expr->args.size() == 2
    206218                        // infix assignment operators => assignment, which is not constant
    207                         std::pair<long long int, bool> arg1, arg2;
     219                        Evaluation arg1, arg2;
    208220                        arg1 = eval(expr->args.front());
    209                         valid &= arg1.second;
    210                         if ( ! valid ) return;
     221                        result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
     222                        if ( ! result.isEvaluableInGCC ) return;
    211223                        arg2 = eval(expr->args.back());
    212                         valid &= arg2.second;
    213                         if ( ! valid ) return;
     224                        result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
     225                        if ( ! result.isEvaluableInGCC ) return;
     226
     227                        result.hasKnownValue &= arg1.hasKnownValue;
     228                        result.hasKnownValue &= arg2.hasKnownValue;
     229                        if ( ! result.hasKnownValue ) return;
    214230
    215231                        if (fname == "?+?") {
    216                                 value = arg1.first + arg2.first;
     232                                result.knownValue = arg1.knownValue + arg2.knownValue;
    217233                        } else if (fname == "?-?") {
    218                                 value = arg1.first - arg2.first;
     234                                result.knownValue = arg1.knownValue - arg2.knownValue;
    219235                        } else if (fname == "?*?") {
    220                                 value = arg1.first * arg2.first;
     236                                result.knownValue = arg1.knownValue * arg2.knownValue;
    221237                        } else if (fname == "?/?") {
    222                                 if ( arg2.first ) value = arg1.first / arg2.first;
     238                                if ( arg2.knownValue ) result.knownValue = arg1.knownValue / arg2.knownValue;
    223239                        } else if (fname == "?%?") {
    224                                 if ( arg2.first ) value = arg1.first % arg2.first;
     240                                if ( arg2.knownValue ) result.knownValue = arg1.knownValue % arg2.knownValue;
    225241                        } else if (fname == "?<<?") {
    226                                 value = arg1.first << arg2.first;
     242                                result.knownValue = arg1.knownValue << arg2.knownValue;
    227243                        } else if (fname == "?>>?") {
    228                                 value = arg1.first >> arg2.first;
     244                                result.knownValue = arg1.knownValue >> arg2.knownValue;
    229245                        } else if (fname == "?<?") {
    230                                 value = arg1.first < arg2.first;
     246                                result.knownValue = arg1.knownValue < arg2.knownValue;
    231247                        } else if (fname == "?>?") {
    232                                 value = arg1.first > arg2.first;
     248                                result.knownValue = arg1.knownValue > arg2.knownValue;
    233249                        } else if (fname == "?<=?") {
    234                                 value = arg1.first <= arg2.first;
     250                                result.knownValue = arg1.knownValue <= arg2.knownValue;
    235251                        } else if (fname == "?>=?") {
    236                                 value = arg1.first >= arg2.first;
     252                                result.knownValue = arg1.knownValue >= arg2.knownValue;
    237253                        } else if (fname == "?==?") {
    238                                 value = arg1.first == arg2.first;
     254                                result.knownValue = arg1.knownValue == arg2.knownValue;
    239255                        } else if (fname == "?!=?") {
    240                                 value = arg1.first != arg2.first;
     256                                result.knownValue = arg1.knownValue != arg2.knownValue;
    241257                        } else if (fname == "?&?") {
    242                                 value = arg1.first & arg2.first;
     258                                result.knownValue = arg1.knownValue & arg2.knownValue;
    243259                        } else if (fname == "?^?") {
    244                                 value = arg1.first ^ arg2.first;
     260                                result.knownValue = arg1.knownValue ^ arg2.knownValue;
    245261                        } else if (fname == "?|?") {
    246                                 value = arg1.first | arg2.first;
     262                                result.knownValue = arg1.knownValue | arg2.knownValue;
    247263                        } else {
    248                                 valid = false;
     264                                result.isEvaluableInGCC = false;
     265                                result.hasKnownValue = false;
    249266                        }
    250267                } // if
     
    263280}
    264281
    265 std::pair<long long int, bool> eval( const ast::Expr * expr ) {
    266         ast::Pass<EvalNew> ev;
     282Evaluation eval( const ast::Expr * expr ) {
    267283        if ( expr ) {
    268                 expr->accept( ev );
    269                 return std::make_pair( ev.core.value, ev.core.valid );
     284
     285                return ast::Pass<EvalNew>::read(expr);
     286                // Evaluation ret = ast::Pass<EvalNew>::read(expr);
     287                // ret.knownValue = 777;
     288                // return ret;
     289
    270290        } else {
    271                 return std::make_pair( 0, false );
     291                return { 0, false, false };
    272292        }
    273293}
  • src/Common/Eval.h

    rfa5e1aa5 rb7b3e41  
    2323}
    2424
     25struct Evaluation {
     26        long long int knownValue;
     27        bool hasKnownValue;
     28        bool isEvaluableInGCC;
     29};
     30
    2531/// Evaluates expr as a long long int.
    2632/// If second is false, expr could not be evaluated.
    2733std::pair<long long int, bool> eval(const Expression * expr);
    28 std::pair<long long int, bool> eval(const ast::Expr * expr);
     34Evaluation eval(const ast::Expr * expr);
    2935
    3036// Local Variables: //
  • src/Concurrency/Actors.cpp

    rfa5e1aa5 rb7b3e41  
    3838    bool namedDecl = false;
    3939
    40     // finds and sets a ptr to the Allocation enum, which is needed in the next pass
     40    // finds and sets a ptr to the allocation enum, which is needed in the next pass
    4141    void previsit( const EnumDecl * decl ) {
    42         if( decl->name == "Allocation" ) *allocationDecl = decl;
     42        if( decl->name == "allocation" ) *allocationDecl = decl;
    4343    }
    4444
     
    227227                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
    228228                    request new_req;
    229                     Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
     229                    allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
    230230                    __receive_fn fn = (__receive_fn)my_work_fn;
    231231                    new_req{ &receiver, &msg, fn };
     
    246246            ));
    247247           
    248             // Function type is: Allocation (*)( derived_actor &, derived_msg & )
     248            // Function type is: allocation (*)( derived_actor &, derived_msg & )
    249249            FunctionType * derivedReceive = new FunctionType();
    250250            derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
     
    252252            derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    253253
    254             // Generates: Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
     254            // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
    255255            sendBody->push_back( new DeclStmt(
    256256                decl->location,
     
    263263            ));
    264264
    265             // Function type is: Allocation (*)( actor &, message & )
     265            // Function type is: allocation (*)( actor &, message & )
    266266            FunctionType * genericReceive = new FunctionType();
    267267            genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
     
    269269            genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    270270
    271             // Generates: Allocation (*fn)( actor &, message & ) = (Allocation (*)( actor &, message & ))my_work_fn;
     271            // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
    272272            // More readable synonymous code:
    273             //     typedef Allocation (*__receive_fn)(actor &, message &);
     273            //     typedef allocation (*__receive_fn)(actor &, message &);
    274274            //     __receive_fn fn = (__receive_fn)my_work_fn;
    275275            sendBody->push_back( new DeclStmt(
     
    285285            ));
    286286
    287             // Generates: new_req{ &receiver, &msg, fn };
     287            // Generates: new_req{ &receiver, (actor *)&receiver, &msg, (message *)&msg, fn };
    288288            sendBody->push_back( new ExprStmt(
    289289                decl->location,
     
    294294                                                new NameExpr( decl->location, "new_req" ),
    295295                        new AddressExpr( new NameExpr( decl->location, "receiver" ) ),
     296                        new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
    296297                        new AddressExpr( new NameExpr( decl->location, "msg" ) ),
     298                        new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
    297299                        new NameExpr( decl->location, "fn" )
    298300                                        }
     
    321323            FunctionDecl * sendOperatorFunction = new FunctionDecl(
    322324                decl->location,
    323                 "?<<?",
     325                "?|?",
    324326                {},                     // forall
    325327                {
     
    422424    const StructDecl ** msgDecl = &msgDeclPtr;
    423425
    424     // first pass collects ptrs to Allocation enum, request type, and generic receive fn typedef
     426    // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
    425427    // also populates maps of all derived actors and messages
    426428    Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
  • src/GenPoly/SpecializeNew.cpp

    rfa5e1aa5 rb7b3e41  
    113113        using namespace ResolvExpr;
    114114        ast::OpenVarSet openVars, closedVars;
    115         ast::AssertionSet need, have;
    116         findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed );
    117         findOpenVars( actualType, openVars, closedVars, need, have, FirstOpen );
     115        ast::AssertionSet need, have; // unused
     116        ast::TypeEnvironment env; // unused
     117        // findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed );
     118        findOpenVars( actualType, openVars, closedVars, need, have, env, FirstOpen );
    118119        for ( const ast::OpenVarSet::value_type & openVar : openVars ) {
    119120                const ast::Type * boundType = subs->lookup( openVar.first );
     
    125126                        if ( closedVars.find( *inst ) == closedVars.end() ) {
    126127                                return true;
     128                        }
     129                        else {
     130                                assertf(false, "closed: %s", inst->name.c_str());
    127131                        }
    128132                // Otherwise, the variable is bound to a concrete type.
  • src/Parser/DeclarationNode.cc

    rfa5e1aa5 rb7b3e41  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 12:34:05 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr 20 11:46:00 2023
    13 // Update Count     : 1393
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jun 17 14:41:48 2023
     13// Update Count     : 1405
    1414//
    1515
     
    459459        std::vector<ast::ptr<ast::Expr>> exprs;
    460460        buildList( expr, exprs );
    461         newnode->attributes.push_back(
    462                 new ast::Attribute( *name, std::move( exprs ) ) );
     461        newnode->attributes.push_back( new ast::Attribute( *name, std::move( exprs ) ) );
    463462        delete name;
    464463        return newnode;
     
    633632                                        dst->basictype = src->basictype;
    634633                                } else if ( src->basictype != DeclarationNode::NoBasicType )
    635                                         SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::basicTypeNames[ src->basictype ] + " in type: " );
     634                                        SemanticError( yylloc, string( "multiple declaration types \"" ) + DeclarationNode::basicTypeNames[ dst->basictype ] +
     635                                                                   "\" and \"" + DeclarationNode::basicTypeNames[ src->basictype ] + "\"." );
    636636
    637637                                if ( dst->complextype == DeclarationNode::NoComplexType ) {
    638638                                        dst->complextype = src->complextype;
    639639                                } else if ( src->complextype != DeclarationNode::NoComplexType )
    640                                         SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::complexTypeNames[ src->complextype ] + " in type: " );
     640                                        SemanticError( yylloc, string( "multiple declaration types \"" ) + DeclarationNode::complexTypeNames[ src->complextype ] +
     641                                                                   "\" and \"" + DeclarationNode::complexTypeNames[ src->complextype ] + "\"." );
    641642
    642643                                if ( dst->signedness == DeclarationNode::NoSignedness ) {
    643644                                        dst->signedness = src->signedness;
    644645                                } else if ( src->signedness != DeclarationNode::NoSignedness )
    645                                         SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::signednessNames[ src->signedness ] + " in type: " );
     646                                        SemanticError( yylloc, string( "conflicting type specifier \"" ) + DeclarationNode::signednessNames[ dst->signedness ] +
     647                                                                   "\" and \"" + DeclarationNode::signednessNames[ src->signedness ] + "\"." );
    646648
    647649                                if ( dst->length == DeclarationNode::NoLength ) {
     
    650652                                        dst->length = DeclarationNode::LongLong;
    651653                                } else if ( src->length != DeclarationNode::NoLength )
    652                                         SemanticError( yylloc, src, string( "conflicting type specifier " ) + DeclarationNode::lengthNames[ src->length ] + " in type: " );
     654                                        SemanticError( yylloc, string( "conflicting type specifier \"" ) + DeclarationNode::lengthNames[ dst->length ] +
     655                                                                   "\" and \"" + DeclarationNode::lengthNames[ src->length ] + "\"." );
    653656                        } // if
    654657                        break;
     
    718721
    719722DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) {
    720         if ( o && o -> type)  {
     723        if ( o && o->type)  {
    721724                type->base= o->type;
    722         }
     725        } // if
    723726        delete o;
    724727        return this;
     
    10031006}
    10041007
    1005 // If a typedef wraps an anonymous declaration, name the inner declaration
    1006 // so it has a consistent name across translation units.
     1008// If a typedef wraps an anonymous declaration, name the inner declaration so it has a consistent name across
     1009// translation units.
    10071010static void nameTypedefedDecl(
    10081011                DeclarationNode * innerDecl,
     
    10851088}
    10861089
    1087 void buildList( DeclarationNode * firstNode,
    1088                 std::vector<ast::ptr<ast::Decl>> & outputList ) {
     1090void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList ) {
    10891091        SemanticErrorException errors;
    10901092        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
  • src/Parser/ExpressionNode.cc

    rfa5e1aa5 rb7b3e41  
    601601ast::Expr * build_cast( const CodeLocation & location,
    602602                DeclarationNode * decl_node,
    603                 ExpressionNode * expr_node ) {
     603                ExpressionNode * expr_node,
     604                ast::CastExpr::CastKind kind ) {
    604605        ast::Type * targetType = maybeMoveBuildType( decl_node );
    605606        if ( dynamic_cast<ast::VoidType *>( targetType ) ) {
     
    607608                return new ast::CastExpr( location,
    608609                        maybeMoveBuild( expr_node ),
    609                         ast::ExplicitCast );
     610                        ast::ExplicitCast, kind );
    610611        } else {
    611612                return new ast::CastExpr( location,
    612613                        maybeMoveBuild( expr_node ),
    613614                        targetType,
    614                         ast::ExplicitCast );
     615                        ast::ExplicitCast, kind );
    615616        } // if
    616617} // build_cast
  • src/Parser/ExpressionNode.h

    rfa5e1aa5 rb7b3e41  
    6969ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
    7070
    71 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
     71ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node, ast::CastExpr::CastKind kind = ast::CastExpr::Default );
    7272ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
    7373ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
  • src/Parser/lex.ll

    rfa5e1aa5 rb7b3e41  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Tue May  2 08:45:21 2023
    13  * Update Count     : 769
     12 * Last Modified On : Fri Jun  9 10:04:00 2023
     13 * Update Count     : 770
    1414 */
    1515
     
    319319static                  { KEYWORD_RETURN(STATIC); }
    320320_Static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C11
     321_static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C23
    321322struct                  { KEYWORD_RETURN(STRUCT); }
    322323suspend                 { KEYWORD_RETURN(SUSPEND); }                    // CFA
  • src/Parser/parser.yy

    rfa5e1aa5 rb7b3e41  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 26 16:45:37 2023
    13 // Update Count     : 6330
     12// Last Modified On : Sat Jun 17 18:53:24 2023
     13// Update Count     : 6347
    1414//
    1515
     
    108108        assert( declList );
    109109        // printf( "distAttr1 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout );
    110         DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( typeSpec );
     110        DeclarationNode * cl = (new DeclarationNode)->addType( typeSpec );
    111111        // printf( "distAttr2 cl %p\n", cl ); cl->type->print( std::cout );
    112112        // cl->type->aggregate.name = cl->type->aggInst.aggregate->aggregate.name;
    113113
    114         for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
     114        for ( DeclarationNode * cur = dynamic_cast<DeclarationNode *>( declList->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
    115115                cl->cloneBaseType( cur );
    116116        } // for
     
    206206#define NEW_ONE  new ExpressionNode( build_constantInteger( yylloc, *new string( "1" ) ) )
    207207#define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right)
    208 #define MISSING_ANON_FIELD "Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."
    209 #define MISSING_LOW "Missing low value for up-to range so index is uninitialized."
    210 #define MISSING_HIGH "Missing high value for down-to range so index is uninitialized."
     208#define MISSING_ANON_FIELD "syntax error, missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."
     209#define MISSING_LOW "syntax error, missing low value for up-to range so index is uninitialized."
     210#define MISSING_HIGH "syntax error, missing high value for down-to range so index is uninitialized."
    211211
    212212static ForCtrl * makeForCtrl(
     
    232232ForCtrl * forCtrl( const CodeLocation & location, DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    233233        if ( index->initializer ) {
    234                 SemanticError( yylloc, "Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );
     234                SemanticError( yylloc, "syntax error, direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );
    235235        } // if
    236236        if ( index->next ) {
    237                 SemanticError( yylloc, "Multiple loop indexes disallowed in for-loop declaration." );
     237                SemanticError( yylloc, "syntax error, multiple loop indexes disallowed in for-loop declaration." );
    238238        } // if
    239239        DeclarationNode * initDecl = index->addInitializer( new InitializerNode( start ) );
     
    260260                        return forCtrl( location, type, new string( identifier->name ), start, compop, comp, inc );
    261261                } else {
    262                         SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     262                        SemanticError( yylloc, "syntax error, loop-index name missing. Expression disallowed." ); return nullptr;
    263263                } // if
    264264        } else {
    265                 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     265                SemanticError( yylloc, "syntax error, loop-index name missing. Expression disallowed. ." ); return nullptr;
    266266        } // if
    267267} // forCtrl
    268268
    269269static void IdentifierBeforeIdentifier( string & identifier1, string & identifier2, const char * kind ) {
    270         SemanticError( yylloc, ::toString( "Adjacent identifiers \"", identifier1, "\" and \"", identifier2, "\" are not meaningful in a", kind, ".\n"
     270        SemanticError( yylloc, ::toString( "syntax error, adjacent identifiers \"", identifier1, "\" and \"", identifier2, "\" are not meaningful in a", kind, ".\n"
    271271                                   "Possible cause is misspelled type name or missing generic parameter." ) );
    272272} // IdentifierBeforeIdentifier
    273273
    274274static void IdentifierBeforeType( string & identifier, const char * kind ) {
    275         SemanticError( yylloc, ::toString( "Identifier \"", identifier, "\" cannot appear before a ", kind, ".\n"
     275        SemanticError( yylloc, ::toString( "syntax error, identifier \"", identifier, "\" cannot appear before a ", kind, ".\n"
    276276                                   "Possible cause is misspelled storage/CV qualifier, misspelled typename, or missing generic parameter." ) );
    277277} // IdentifierBeforeType
     
    689689        // | RESUME '(' comma_expression ')' compound_statement
    690690        //      { SemanticError( yylloc, "Resume expression is currently unimplemented." ); $$ = nullptr; }
    691         | IDENTIFIER IDENTIFIER                                                         // syntax error
     691        | IDENTIFIER IDENTIFIER                                                         // invalid syntax rules
    692692                { IdentifierBeforeIdentifier( *$1.str, *$2.str, "n expression" ); $$ = nullptr; }
    693         | IDENTIFIER type_qualifier                                                     // syntax error
     693        | IDENTIFIER type_qualifier                                                     // invalid syntax rules
    694694                { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; }
    695         | IDENTIFIER storage_class                                                      // syntax error
     695        | IDENTIFIER storage_class                                                      // invalid syntax rules
    696696                { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; }
    697         | IDENTIFIER basic_type_name                                            // syntax error
     697        | IDENTIFIER basic_type_name                                            // invalid syntax rules
    698698                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    699         | IDENTIFIER TYPEDEFname                                                        // syntax error
     699        | IDENTIFIER TYPEDEFname                                                        // invalid syntax rules
    700700                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    701         | IDENTIFIER TYPEGENname                                                        // syntax error
     701        | IDENTIFIER TYPEGENname                                                        // invalid syntax rules
    702702                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    703703        ;
     
    931931                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); }
    932932        | '(' RETURN type_no_function ')' cast_expression       // CFA
    933                 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }
     933                { $$ = new ExpressionNode( build_cast( yylloc, $3, $5, ast::CastExpr::Return ) ); }
    934934        | '(' COERCE type_no_function ')' cast_expression       // CFA
    935935                { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }
     
    10401040                // FIX ME: computes $1 twice
    10411041        | logical_OR_expression '?' /* empty */ ':' conditional_expression // GCC, omitted first operand
    1042                 { $$ = new ExpressionNode( build_cond( yylloc, $1, $1, $4 ) ); }
     1042                { $$ = new ExpressionNode( build_cond( yylloc, $1, $1->clone(), $4 ) ); }
    10431043        ;
    10441044
     
    11521152        identifier_or_type_name ':' attribute_list_opt statement
    11531153                { $$ = $4->add_label( yylloc, $1, $3 ); }
    1154         | identifier_or_type_name ':' attribute_list_opt error // syntax error
    1155                 {
    1156                         SemanticError( yylloc, ::toString( "Label \"", *$1.str, "\" must be associated with a statement, "
     1154        | identifier_or_type_name ':' attribute_list_opt error // invalid syntax rule
     1155                {
     1156                        SemanticError( yylloc, ::toString( "syntx error, label \"", *$1.str, "\" must be associated with a statement, "
    11571157                                                                                           "where a declaration, case, or default is not a statement. "
    11581158                                                                                           "Move the label or terminate with a semi-colon." ) );
     
    11931193        | statement_list_nodecl statement
    11941194                { assert( $1 ); $1->set_last( $2 ); $$ = $1; }
    1195         | statement_list_nodecl error                                           // syntax error
    1196                 { SemanticError( yylloc, "Declarations only allowed at the start of the switch body, i.e., after the '{'." ); $$ = nullptr; }
     1195        | statement_list_nodecl error                                           // invalid syntax rule
     1196                { SemanticError( yylloc, "syntax error, declarations only allowed at the start of the switch body, i.e., after the '{'." ); $$ = nullptr; }
    11971197        ;
    11981198
     
    12191219                        $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    12201220                }
    1221         | SWITCH '(' comma_expression ')' '{' error '}'         // CFA, syntax error
    1222                 { SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
     1221        | SWITCH '(' comma_expression ')' '{' error '}'         // CFA, invalid syntax rule error
     1222                { SemanticError( yylloc, "synatx error, declarations can only appear before the list of case clauses." ); $$ = nullptr; }
    12231223        | CHOOSE '(' comma_expression ')' case_clause           // CFA
    12241224                { $$ = new StatementNode( build_switch( yylloc, false, $3, $5 ) ); }
     
    12281228                        $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
    12291229                }
    1230         | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, syntax error
    1231                 { SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
     1230        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, invalid syntax rule
     1231                { SemanticError( yylloc, "syntax error, declarations can only appear before the list of case clauses." ); $$ = nullptr; }
    12321232        ;
    12331233
     
    12681268
    12691269case_label:                                                                                             // CFA
    1270         CASE error                                                                                      // syntax error
    1271                 { SemanticError( yylloc, "Missing case list after case." ); $$ = nullptr; }
     1270        CASE error                                                                                      // invalid syntax rule
     1271                { SemanticError( yylloc, "syntax error, case list missing after case." ); $$ = nullptr; }
    12721272        | CASE case_value_list ':'                                      { $$ = $2; }
    1273         | CASE case_value_list error                                            // syntax error
    1274                 { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
     1273        | CASE case_value_list error                                            // invalid syntax rule
     1274                { SemanticError( yylloc, "syntax error, colon missing after case list." ); $$ = nullptr; }
    12751275        | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
    12761276                // A semantic check is required to ensure only one default clause per switch/choose statement.
    1277         | DEFAULT error                                                                         //  syntax error
    1278                 { SemanticError( yylloc, "Missing colon after default." ); $$ = nullptr; }
     1277        | DEFAULT error                                                                         //  invalid syntax rules
     1278                { SemanticError( yylloc, "syntax error, colon missing after default." ); $$ = nullptr; }
    12791279        ;
    12801280
     
    14051405                        else { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14061406                }
    1407         | comma_expression updowneq comma_expression '~' '@' // CFA, error
     1407        | comma_expression updowneq comma_expression '~' '@' // CFA, invalid syntax rules
    14081408                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1409         | '@' updowneq '@'                                                                      // CFA, error
     1409        | '@' updowneq '@'                                                                      // CFA, invalid syntax rules
    14101410                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1411         | '@' updowneq comma_expression '~' '@'                         // CFA, error
     1411        | '@' updowneq comma_expression '~' '@'                         // CFA, invalid syntax rules
    14121412                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1413         | comma_expression updowneq '@' '~' '@'                         // CFA, error
     1413        | comma_expression updowneq '@' '~' '@'                         // CFA, invalid syntax rules
    14141414                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1415         | '@' updowneq '@' '~' '@'                                                      // CFA, error
     1415        | '@' updowneq '@' '~' '@'                                                      // CFA, invalid syntax rules
    14161416                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    14171417
     
    14311431                {
    14321432                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    1433                         else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
     1433                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    14341434                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
    14351435                }
    1436         | comma_expression ';' '@' updowneq '@'                         // CFA, error
    1437                 { SemanticError( yylloc, "Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
     1436        | comma_expression ';' '@' updowneq '@'                         // CFA, invalid syntax rules
     1437                { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
    14381438
    14391439        | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA
    14401440                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
    1441         | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error
     1441        | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, invalid syntax rules
    14421442                {
    14431443                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
     
    14471447                {
    14481448                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    1449                         else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
     1449                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    14501450                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, $7 );
    14511451                }
    14521452        | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA
    14531453                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
    1454         | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error
     1454        | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rules
    14551455                {
    14561456                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
     
    14601460                {
    14611461                        if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    1462                         else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
     1462                        else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    14631463                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, nullptr );
    14641464                }
    14651465        | comma_expression ';' '@' updowneq '@' '~' '@' // CFA
    1466                 { SemanticError( yylloc, "Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
     1466                { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
    14671467
    14681468        | declaration comma_expression                                          // CFA
     
    14811481                {
    14821482                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    1483                         else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
     1483                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    14841484                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, NEW_ONE );
    14851485                }
     
    14951495                {
    14961496                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    1497                         else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
     1497                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    14981498                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, $6 );
    14991499                }
     
    15081508                {
    15091509                        if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    1510                         else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
     1510                        else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "syntax error, equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
    15111511                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr );
    15121512                }
    1513         | declaration '@' updowneq '@' '~' '@'                          // CFA, error
    1514                 { SemanticError( yylloc, "Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
     1513        | declaration '@' updowneq '@' '~' '@'                          // CFA, invalid syntax rules
     1514                { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
    15151515
    15161516        | comma_expression ';' TYPEDEFname                                      // CFA, array type
     
    15211521        | comma_expression ';' downupdowneq TYPEDEFname         // CFA, array type
    15221522                {
    1523                         if ( $3 == OperKinds::LEThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, "All enumation ranges are equal (all values). Remove \"=~\"." ); $$ = nullptr; }
     1523                        if ( $3 == OperKinds::LEThan || $3 == OperKinds::GEThan ) {
     1524                                SemanticError( yylloc, "syntax error, all enumeration ranges are equal (all values). Remove \"=~\"." ); $$ = nullptr;
     1525                        }
    15241526                        SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr;
    15251527                }
     
    16161618        MUTEX '(' argument_expression_list_opt ')' statement
    16171619                {
    1618                         if ( ! $3 ) { SemanticError( yylloc, "mutex argument list cannot be empty." ); $$ = nullptr; }
     1620                        if ( ! $3 ) { SemanticError( yylloc, "syntax error, mutex argument list cannot be empty." ); $$ = nullptr; }
    16191621                        $$ = new StatementNode( build_mutex( yylloc, $3, $5 ) );
    16201622                }
     
    16641666                { $$ = build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); }
    16651667        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1666         | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
    1667                 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
     1668        | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules
     1669                { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    16681670        | wor_waitfor_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
    16691671                { $$ = build_waitfor_else( yylloc, build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ), $7, maybe_build_compound( yylloc, $9 ) ); }
     
    17091711                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }
    17101712        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1711         | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
    1712                 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
     1713        | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules
     1714                { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    17131715        | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
    17141716                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1,
     
    20652067                        assert( $1->type );
    20662068                        if ( $1->type->qualifiers.any() ) {                     // CV qualifiers ?
    2067                                 SemanticError( yylloc, "Useless type qualifier(s) in empty declaration." ); $$ = nullptr;
     2069                                SemanticError( yylloc, "syntax error, useless type qualifier(s) in empty declaration." ); $$ = nullptr;
    20682070                        }
    20692071                        // enums are never empty declarations because there must have at least one enumeration.
    20702072                        if ( $1->type->kind == TypeData::AggregateInst && $1->storageClasses.any() ) { // storage class ?
    2071                                 SemanticError( yylloc, "Useless storage qualifier(s) in empty aggregate declaration." ); $$ = nullptr;
     2073                                SemanticError( yylloc, "syntax error, useless storage qualifier(s) in empty aggregate declaration." ); $$ = nullptr;
    20722074                        }
    20732075                }
     
    21002102        | type_declaration_specifier
    21012103        | sue_declaration_specifier
    2102         | sue_declaration_specifier invalid_types
    2103                 {
    2104                         SemanticError( yylloc, ::toString( "Missing ';' after end of ",
     2104        | sue_declaration_specifier invalid_types                       // invalid syntax rule
     2105                {
     2106                        SemanticError( yylloc, ::toString( "syntax error, expecting ';' at end of ",
    21052107                                $1->type->enumeration.name ? "enum" : ast::AggregateDecl::aggrString( $1->type->aggregate.kind ),
    2106                                 " declaration" ) );
     2108                                " declaration." ) );
    21072109                        $$ = nullptr;
    21082110                }
     
    25842586                        // } // for
    25852587                }
     2588        | type_specifier field_declaring_list_opt '}'           // invalid syntax rule
     2589                {
     2590                        SemanticError( yylloc, ::toString( "syntax error, expecting ';' at end of previous declaration." ) );
     2591                        $$ = nullptr;
     2592                }
    25862593        | EXTENSION type_specifier field_declaring_list_opt ';' // GCC
    25872594                { $$ = fieldDecl( $2, $3 ); distExt( $$ ); }
     
    26822689        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    26832690                {
    2684                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() )
    2685                         { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    2686 
     2691                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() ) {
     2692                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
     2693                        }
    26872694                        $$ = DeclarationNode::newEnum( nullptr, $7, true, true, $3 )->addQualifiers( $5 );
    26882695                }
     
    26932700        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    26942701                {
    2695                         if ( $3->storageClasses.any() || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     2702                        if ( $3->storageClasses.any() || $3->type->qualifiers.val != 0 ) {
     2703                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
     2704                        }
    26962705                        typedefTable.makeTypedef( *$6 );
    26972706                }
     
    31663175        | IDENTIFIER IDENTIFIER
    31673176                { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; }
    3168         | IDENTIFIER type_qualifier                                                     // syntax error
     3177        | IDENTIFIER type_qualifier                                                     // invalid syntax rules
    31693178                { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; }
    3170         | IDENTIFIER storage_class                                                      // syntax error
     3179        | IDENTIFIER storage_class                                                      // invalid syntax rules
    31713180                { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; }
    3172         | IDENTIFIER basic_type_name                                            // syntax error
     3181        | IDENTIFIER basic_type_name                                            // invalid syntax rules
    31733182                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    3174         | IDENTIFIER TYPEDEFname                                                        // syntax error
     3183        | IDENTIFIER TYPEDEFname                                                        // invalid syntax rules
    31753184                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    3176         | IDENTIFIER TYPEGENname                                                        // syntax error
     3185        | IDENTIFIER TYPEGENname                                                        // invalid syntax rules
    31773186                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    31783187        | external_function_definition
     
    32093218        | type_qualifier_list
    32103219                {
    3211                         if ( $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3220                        if ( $1->type->qualifiers.any() ) {
     3221                                SemanticError( yylloc, "syntax error, CV qualifiers cannot be distributed; only storage-class and forall qualifiers." );
     3222                        }
    32123223                        if ( $1->type->forall ) forall = true;          // remember generic type
    32133224                }
     
    32203231        | declaration_qualifier_list
    32213232                {
    3222                         if ( $1->type && $1->type->qualifiers.any() ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3233                        if ( $1->type && $1->type->qualifiers.any() ) {
     3234                                SemanticError( yylloc, "syntax error, CV qualifiers cannot be distributed; only storage-class and forall qualifiers." );
     3235                        }
    32233236                        if ( $1->type && $1->type->forall ) forall = true; // remember generic type
    32243237                }
     
    32313244        | declaration_qualifier_list type_qualifier_list
    32323245                {
    3233                         if ( ($1->type && $1->type->qualifiers.any()) || ($2->type && $2->type->qualifiers.any()) ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); }
     3246                        if ( ($1->type && $1->type->qualifiers.any()) || ($2->type && $2->type->qualifiers.any()) ) {
     3247                                SemanticError( yylloc, "syntax error, CV qualifiers cannot be distributed; only storage-class and forall qualifiers." );
     3248                        }
    32343249                        if ( ($1->type && $1->type->forall) || ($2->type && $2->type->forall) ) forall = true; // remember generic type
    32353250                }
     
    32623277                        $$ = $3; forall = false;
    32633278                        if ( $5 ) {
    3264                                 SemanticError( yylloc, "Attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." );
     3279                                SemanticError( yylloc, "syntax error, attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." );
    32653280                                $$ = nullptr;
    32663281                        } // if
  • src/ResolvExpr/Candidate.hpp

    rfa5e1aa5 rb7b3e41  
    9191
    9292/// Holdover behaviour from old `findMinCost` -- xxx -- can maybe be eliminated?
     93/*
    9394static inline void promoteCvtCost( CandidateList & candidates ) {
    9495        for ( CandidateRef & r : candidates ) {
     
    9697        }
    9798}
     99*/
    98100
    99101void print( std::ostream & os, const Candidate & cand, Indenter indent = {} );
  • src/ResolvExpr/CandidateFinder.cpp

    rfa5e1aa5 rb7b3e41  
    3838#include "typeops.h"              // for combos
    3939#include "Unify.h"
     40#include "WidenMode.h"
    4041#include "AST/Expr.hpp"
    4142#include "AST/Node.hpp"
     
    749750                        // attempt to narrow based on expected target type
    750751                        const ast::Type * returnType = funcType->returns.front();
    751                         if ( ! unify(
    752                                 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )
    753                         ) {
    754                                 // unification failed, do not pursue this candidate
    755                                 return;
     752                        if ( selfFinder.strictMode ) {
     753                                if ( ! unifyExact(
     754                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct?
     755                                ) {
     756                                        // unification failed, do not pursue this candidate
     757                                        return;
     758                                }
     759                        }
     760                        else {
     761                                if ( ! unify(
     762                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )
     763                                ) {
     764                                        // unification failed, do not pursue this candidate
     765                                        return;
     766                                }
    756767                        }
    757768                }
     
    771782                                for (size_t i=0; i<nParams; ++i) {
    772783                                        auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    773                                         if (!instantiateArgument( location,
     784                                        if ( !instantiateArgument( location,
    774785                                                funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    775786                                }
     
    781792                        // matches
    782793                        // no default args for indirect calls
    783                         if ( ! instantiateArgument( location,
     794                        if ( !instantiateArgument( location,
    784795                                param, nullptr, args, results, genStart, symtab ) ) return;
    785796                }
     
    874885
    875886                if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    876                         addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
     887                        addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" );
    877888                } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    878                         addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
     889                        addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
    879890                }
    880891        }
     
    10071018                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    10081019                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1020                                                // if (!selfFinder.allowVoid && function->returns.empty()) continue;
    10091021                                                CandidateRef newFunc{ new Candidate{ *func } };
    10101022                                                newFunc->expr =
     
    10181030                                        if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    10191031                                                if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    1020                                                         CandidateRef newFunc{ new Candidate{ *func } };
     1032                                                        CandidateRef newFunc( new Candidate( *func ) );
    10211033                                                        newFunc->expr =
    10221034                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     
    10601072                if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    10611073
     1074                // only keep the best matching intrinsic result to match C semantics (no unexpected narrowing/widening)
     1075                // TODO: keep one for each set of argument candidates?
     1076                Cost intrinsicCost = Cost::infinity;
     1077                CandidateList intrinsicResult;
     1078
    10621079                // Compute conversion costs
    10631080                for ( CandidateRef & withFunc : found ) {
     
    10821099                        if ( cvtCost != Cost::infinity ) {
    10831100                                withFunc->cvtCost = cvtCost;
    1084                                 candidates.emplace_back( std::move( withFunc ) );
    1085                         }
    1086                 }
     1101                                withFunc->cost += cvtCost;
     1102                                auto func = withFunc->expr.strict_as<ast::ApplicationExpr>()->func.as<ast::VariableExpr>();
     1103                                if (func && func->var->linkage == ast::Linkage::Intrinsic) {
     1104                                        if (withFunc->cost < intrinsicCost) {
     1105                                                intrinsicResult.clear();
     1106                                                intrinsicCost = withFunc->cost;
     1107                                        }
     1108                                        if (withFunc->cost == intrinsicCost) {
     1109                                                intrinsicResult.emplace_back(std::move(withFunc));
     1110                                        }
     1111                                }
     1112                                else {
     1113                                        candidates.emplace_back( std::move( withFunc ) );
     1114                                }
     1115                        }
     1116                }
     1117                spliceBegin( candidates, intrinsicResult );
    10871118                found = std::move( candidates );
    10881119
    10891120                // use a new list so that candidates are not examined by addAnonConversions twice
    1090                 CandidateList winners = findMinCost( found );
    1091                 promoteCvtCost( winners );
     1121                // CandidateList winners = findMinCost( found );
     1122                // promoteCvtCost( winners );
    10921123
    10931124                // function may return a struct/union value, in which case we need to add candidates
    10941125                // for implicit conversions to each of the anonymous members, which must happen after
    10951126                // `findMinCost`, since anon conversions are never the cheapest
    1096                 for ( const CandidateRef & c : winners ) {
     1127                for ( const CandidateRef & c : found ) {
    10971128                        addAnonConversions( c );
    10981129                }
    1099                 spliceBegin( candidates, winners );
    1100 
    1101                 if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     1130                // would this be too slow when we don't check cost anymore?
     1131                spliceBegin( candidates, found );
     1132
     1133                if ( candidates.empty() && targetType && ! targetType->isVoid() && !selfFinder.strictMode ) {
    11021134                        // If resolution is unsuccessful with a target type, try again without, since it
    11031135                        // will sometimes succeed when it wouldn't with a target type binding.
     
    11401172
    11411173                CandidateFinder finder( context, tenv, toType );
     1174                if (toType->isVoid()) {
     1175                        finder.allowVoid = true;
     1176                }
     1177                if ( castExpr->kind == ast::CastExpr::Return ) {
     1178                        finder.strictMode = true;
     1179                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1180
     1181                        // return casts are eliminated (merely selecting an overload, no actual operation)
     1182                        candidates = std::move(finder.candidates);
     1183                }
    11421184                finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    11431185
     
    11451187
    11461188                CandidateList matches;
     1189                Cost minExprCost = Cost::infinity;
     1190                Cost minCastCost = Cost::infinity;
    11471191                for ( CandidateRef & cand : finder.candidates ) {
    11481192                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    11761220                                // count one safe conversion for each value that is thrown away
    11771221                                thisCost.incSafe( discardedValues );
    1178                                 CandidateRef newCand = std::make_shared<Candidate>(
    1179                                         restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1180                                         copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
    1181                                         cand->cost + thisCost );
    1182                                 inferParameters( newCand, matches );
    1183                         }
    1184                 }
    1185 
    1186                 // select first on argument cost, then conversion cost
    1187                 CandidateList minArgCost = findMinCost( matches );
    1188                 promoteCvtCost( minArgCost );
    1189                 candidates = findMinCost( minArgCost );
     1222                                // select first on argument cost, then conversion cost
     1223                                if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) {
     1224                                        minExprCost = cand->cost;
     1225                                        minCastCost = thisCost;
     1226                                        matches.clear();
     1227
     1228
     1229                                }
     1230                                // ambiguous case, still output candidates to print in error message
     1231                                if ( cand->cost == minExprCost && thisCost == minCastCost ) {
     1232                                        CandidateRef newCand = std::make_shared<Candidate>(
     1233                                                restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1234                                                copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);
     1235                                        // currently assertions are always resolved immediately so this should have no effect.
     1236                                        // if this somehow changes in the future (e.g. delayed by indeterminate return type)
     1237                                        // we may need to revisit the logic.
     1238                                        inferParameters( newCand, matches );
     1239                                }
     1240                                // else skip, better alternatives found
     1241
     1242                        }
     1243                }
     1244                candidates = std::move(matches);
     1245
     1246                //CandidateList minArgCost = findMinCost( matches );
     1247                //promoteCvtCost( minArgCost );
     1248                //candidates = findMinCost( minArgCost );
    11901249        }
    11911250
     
    14531512                // candidates for true result
    14541513                CandidateFinder finder2( context, tenv );
     1514                finder2.allowVoid = true;
    14551515                finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    14561516                if ( finder2.candidates.empty() ) return;
     
    14581518                // candidates for false result
    14591519                CandidateFinder finder3( context, tenv );
     1520                finder3.allowVoid = true;
    14601521                finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    14611522                if ( finder3.candidates.empty() ) return;
     
    15241585        void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) {
    15251586                CandidateFinder finder( context, tenv );
     1587                finder.allowVoid = true;
    15261588                finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    15271589                for ( CandidateRef & r : finder.candidates ) {
     
    16401702                        CandidateFinder finder( context, tenv, toType );
    16411703                        finder.find( initExpr->expr, ResolvMode::withAdjustment() );
     1704
     1705                        Cost minExprCost = Cost::infinity;
     1706                        Cost minCastCost = Cost::infinity;
    16421707                        for ( CandidateRef & cand : finder.candidates ) {
    16431708                                if (reason.code == NotFound) reason.code = NoMatch;
     
    16771742                                        // count one safe conversion for each value that is thrown away
    16781743                                        thisCost.incSafe( discardedValues );
    1679                                         CandidateRef newCand = std::make_shared<Candidate>(
    1680                                                 new ast::InitExpr{
    1681                                                         initExpr->location, restructureCast( cand->expr, toType ),
    1682                                                         initAlt.designation },
    1683                                                 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
    1684                                         inferParameters( newCand, matches );
     1744                                        if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) {
     1745                                                minExprCost = cand->cost;
     1746                                                minCastCost = thisCost;
     1747                                                matches.clear();
     1748                                        }
     1749                                        // ambiguous case, still output candidates to print in error message
     1750                                        if ( cand->cost == minExprCost && thisCost == minCastCost ) {
     1751                                                CandidateRef newCand = std::make_shared<Candidate>(
     1752                                                        new ast::InitExpr{
     1753                                                                initExpr->location,
     1754                                                                restructureCast( cand->expr, toType ),
     1755                                                                initAlt.designation },
     1756                                                        std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
     1757                                                // currently assertions are always resolved immediately so this should have no effect.
     1758                                                // if this somehow changes in the future (e.g. delayed by indeterminate return type)
     1759                                                // we may need to revisit the logic.
     1760                                                inferParameters( newCand, matches );
     1761                                        }
    16851762                                }
    16861763                        }
     
    16881765
    16891766                // select first on argument cost, then conversion cost
    1690                 CandidateList minArgCost = findMinCost( matches );
    1691                 promoteCvtCost( minArgCost );
    1692                 candidates = findMinCost( minArgCost );
     1767                // CandidateList minArgCost = findMinCost( matches );
     1768                // promoteCvtCost( minArgCost );
     1769                // candidates = findMinCost( minArgCost );
     1770                candidates = std::move(matches);
    16931771        }
    16941772
     
    17561834                        auto found = selected.find( mangleName );
    17571835                        if ( found != selected.end() ) {
    1758                                 if ( newCand->cost < found->second.candidate->cost ) {
     1836                                // tiebreaking by picking the lower cost on CURRENT expression
     1837                                // NOTE: this behavior is different from C semantics.
     1838                                // Specific remediations are performed for C operators at postvisit(UntypedExpr).
     1839                                // Further investigations may take place.
     1840                                if ( newCand->cost < found->second.candidate->cost
     1841                                        || (newCand->cost == found->second.candidate->cost && newCand->cvtCost < found->second.candidate->cvtCost) ) {
    17591842                                        PRINT(
    17601843                                                std::cerr << "cost " << newCand->cost << " beats "
     
    17631846
    17641847                                        found->second = PruneStruct{ newCand };
    1765                                 } else if ( newCand->cost == found->second.candidate->cost ) {
     1848                                } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost ) {
    17661849                                        // if one of the candidates contains a deleted identifier, can pick the other,
    17671850                                        // since deleted expressions should not be ambiguous if there is another option
     
    18541937        */
    18551938
    1856         if ( mode.prune ) {
     1939        // optimization: don't prune for NameExpr since it never has cost
     1940        if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr) ) {
    18571941                // trim candidates to single best one
    18581942                PRINT(
  • src/ResolvExpr/CandidateFinder.hpp

    rfa5e1aa5 rb7b3e41  
    3333        const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
    3434        ast::ptr< ast::Type > targetType;  ///< Target type for resolution
     35        bool strictMode = false;           ///< If set to true, requires targetType to be exact match (inside return cast)
     36        bool allowVoid = false;            ///< If set to true, allow void-returning function calls (only top level, cast to void and first in comma)
    3537        std::set< std::string > otypeKeys;  /// different type may map to same key
    3638
  • src/ResolvExpr/CastCost.cc

    rfa5e1aa5 rb7b3e41  
    234234        if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
    235235                PRINT( std::cerr << "compatible!" << std::endl; )
     236                if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {
     237                        return Cost::spec;
     238                }
    236239                return Cost::zero;
    237240        } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
  • src/ResolvExpr/CommonType.cc

    rfa5e1aa5 rb7b3e41  
    697697                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
    698698                                #warning remove casts when `commonTypes` moved to new AST
     699                               
     700                                /*
    699701                                ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
    700702                                if (
     
    706708                                        result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
    707709                                }
     710                                */
     711                                ast::BasicType::Kind kind;
     712                                if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
     713                                else if (!widen.first) kind = basic->kind; // widen.second
     714                                else if (!widen.second) kind = basic2->kind;
     715                                else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
     716                                // xxx - what does qualifiers even do here??
     717                                if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
     718                                        && (basic->qualifiers <= basic2->qualifiers || widen.second) ) {
     719                                        result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
     720                                }
     721                               
    708722                        } else if (
    709723                                dynamic_cast< const ast::ZeroType * >( type2 )
     
    712726                                #warning remove casts when `commonTypes` moved to new AST
    713727                                ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
    714                                 if (
    715                                         ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
     728                                /*
     729                                if ( // xxx - what does qualifier even do here??
     730                                        ( ( basic->qualifiers >= type2->qualifiers )
    716731                                                || widen.first )
    717                                         && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
     732                                         && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    718733                                                || widen.second )
    719                                 ) {
    720                                         result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
     734                                )
     735                                */
     736                                if (widen.second) {
     737                                        result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
    721738                                }
    722739                        } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
     
    746763                                auto entry = open.find( *var );
    747764                                if ( entry != open.end() ) {
     765                                // if (tenv.lookup(*var)) {
    748766                                        ast::AssertionSet need, have;
    749767                                        if ( ! tenv.bindVar(
     
    10171035                void postvisit( const ast::TraitInstType * ) {}
    10181036
    1019                 void postvisit( const ast::TypeInstType * inst ) {}
    1020 
    1021                 void postvisit( const ast::TupleType * tuple) {
     1037                void postvisit( const ast::TypeInstType * ) {}
     1038
     1039                void postvisit( const ast::TupleType * tuple ) {
    10221040                        tryResolveWithTypedEnum( tuple );
    10231041                }
  • src/ResolvExpr/ConversionCost.cc

    rfa5e1aa5 rb7b3e41  
    702702
    703703        cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
     704
     705        // xxx - should qualifiers be considered in pass-by-value?
     706        /*
    704707        if ( refType->base->qualifiers == dst->qualifiers ) {
    705708                cost.incReference();
     
    709712                cost.incUnsafe();
    710713        }
     714        */
     715        cost.incReference();
    711716}
    712717
     
    792797                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    793798                }
     799                // this has the effect of letting any expr such as x+0, x+1 to be typed
     800                // the same as x, instead of at least int. are we willing to sacrifice this little
     801                // bit of coherence with C?
     802                // TODO: currently this does not work when no zero/one overloads exist. Find a fix for it.
     803                // cost = Cost::zero;
    794804        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
    795805                cost = Cost::zero;
    796806                // +1 for zero_t ->, +1 for disambiguation
    797807                cost.incSafe( maxIntCost + 2 );
     808                // assuming 0p is supposed to be used for pointers?
    798809        }
    799810}
     
    804815                cost = Cost::zero;
    805816        } else if ( const ast::BasicType * dstAsBasic =
    806                         dynamic_cast< const ast::BasicType * >( dst ) ) {
     817                        dynamic_cast< const ast::BasicType * >( dst ) ) {               
    807818                int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
    808819                if ( -1 == tableResult ) {
     
    813824                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    814825                }
     826               
     827                // cost = Cost::zero;
    815828        }
    816829}
  • src/ResolvExpr/CurrentObject.cc

    rfa5e1aa5 rb7b3e41  
    689689
    690690                        auto arg = eval( expr );
    691                         index = arg.first;
     691                        assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" );
     692                        index = arg.knownValue;
    692693
    693694                        // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    728729                size_t getSize( const Expr * expr ) {
    729730                        auto res = eval( expr );
    730                         if ( !res.second ) {
     731                        if ( !res.hasKnownValue ) {
    731732                                SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
    732733                        }
    733                         return res.first;
     734                        return res.knownValue;
    734735                }
    735736
  • src/ResolvExpr/FindOpenVars.cc

    rfa5e1aa5 rb7b3e41  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
     23#include "AST/TypeEnvironment.hpp"
    2324#include "Common/PassVisitor.h"
    2425#include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
    2526#include "SynTree/Type.h"         // for Type, Type::ForallList, ArrayType
     27
     28#include <iostream>
    2629
    2730namespace ResolvExpr {
     
    102105                        ast::AssertionSet & need;
    103106                        ast::AssertionSet & have;
     107                        ast::TypeEnvironment & env;
    104108                        bool nextIsOpen;
    105109
    106110                        FindOpenVars_new(
    107111                                ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
    108                                 ast::AssertionSet & h, FirstMode firstIsOpen )
    109                         : open( o ), closed( c ), need( n ), have( h ), nextIsOpen( firstIsOpen ) {}
     112                                ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
     113                        : open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {}
    110114
    111115                        void previsit( const ast::FunctionType * type ) {
    112116                                // mark open/closed variables
    113117                                if ( nextIsOpen ) {
     118                                        // trying to remove this from resolver.
     119                                        // occasionally used in other parts so not deleting right now.
     120
     121                                        // insert open variables unbound to environment.
     122                                        env.add(type->forall);
     123
    114124                                        for ( auto & decl : type->forall ) {
    115125                                                open[ *decl ] = ast::TypeData{ decl->base };
     
    137147        void findOpenVars(
    138148                        const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    139                         ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen ) {
    140                 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, firstIsOpen };
     149                        ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
     150                ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, env, firstIsOpen };
    141151                type->accept( finder );
     152
     153                if (!closed.empty()) {
     154                        std::cerr << "closed: ";
     155                        for (auto& i : closed) {
     156                                std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
     157                        }
     158                        std::cerr << std::endl;
     159                }
    142160        }
    143161} // namespace ResolvExpr
  • src/ResolvExpr/FindOpenVars.h

    rfa5e1aa5 rb7b3e41  
    3333        void findOpenVars(
    3434                const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    35                 ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen );
     35                ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen );
    3636} // namespace ResolvExpr
    3737
  • src/ResolvExpr/Resolver.cc

    rfa5e1aa5 rb7b3e41  
    10111011                        ast::TypeEnvironment env;
    10121012                        CandidateFinder finder( context, env );
     1013                        finder.allowVoid = true;
    10131014                        finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
    10141015                        --recursion_level;
     
    10541055
    10551056                        // promote candidate.cvtCost to .cost
    1056                         promoteCvtCost( winners );
     1057                        // promoteCvtCost( winners );
    10571058
    10581059                        // produce ambiguous errors, if applicable
     
    11061107
    11071108                /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
    1108                 void removeExtraneousCast( ast::ptr<ast::Expr> & expr, const ast::SymbolTable & symtab ) {
     1109                void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
    11091110                        if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
    11101111                                if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
     
    11961197                ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
    11971198                ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
    1198                 removeExtraneousCast( newExpr, context.symtab );
     1199                removeExtraneousCast( newExpr );
    11991200                return newExpr;
    12001201        }
     
    12611262                static size_t traceId;
    12621263                Resolver_new( const ast::TranslationGlobal & global ) :
     1264                        ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
    12631265                        context{ symtab, global } {}
    12641266                Resolver_new( const ResolveContext & context ) :
     
    13401342                                        auto mutAttr = mutate(attr);
    13411343                                        mutAttr->params.front() = resolved;
    1342                                         if (! result.second) {
     1344                                        if (! result.hasKnownValue) {
    13431345                                                SemanticWarning(loc, Warning::GccAttributes,
    13441346                                                        toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
    13451347                                        }
    13461348                                        else {
    1347                                                 auto priority = result.first;
     1349                                                auto priority = result.knownValue;
    13481350                                                if (priority < 101) {
    13491351                                                        SemanticWarning(loc, Warning::GccAttributes,
     
    20402042                const ast::Type * initContext = currentObject.getCurrentType();
    20412043
    2042                 removeExtraneousCast( newExpr, symtab );
     2044                removeExtraneousCast( newExpr );
    20432045
    20442046                // check if actual object's type is char[]
  • src/ResolvExpr/SatisfyAssertions.cpp

    rfa5e1aa5 rb7b3e41  
    1616#include "SatisfyAssertions.hpp"
    1717
     18#include <iostream>
    1819#include <algorithm>
    1920#include <cassert>
     
    4546#include "SymTab/Mangler.h"
    4647
     48
     49
    4750namespace ResolvExpr {
    4851
     
    6568                        ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs )
    6669                : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ),
    67                   need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {}
     70                  need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {
     71                        if (!have.empty()) {
     72                                // std::cerr << c.id->location << ':' << c.id->name << std::endl; // I think this was debugging code so I commented it
     73                        }
     74                  }
    6875        };
    6976
     
    139146        };
    140147
    141         /// Adds a captured assertion to the symbol table
    142         void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) {
    143                 for ( auto & i : have ) {
    144                         if ( i.second.isUsed ) { symtab.addId( i.first->var ); }
    145                 }
    146         }
     148        enum AssertionResult {Fail, Skip, Success} ;
    147149
    148150        /// Binds a single assertion, updating satisfaction state
     
    155157                        "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    156158
    157                 ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cvtCost );
     159                ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cost );
    158160                varExpr->result = match.adjType;
    159161                if ( match.resnSlot ) { varExpr->inferred.resnSlots().emplace_back( match.resnSlot ); }
     
    165167
    166168        /// Satisfy a single assertion
    167         bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool allowConversion = false, bool skipUnbound = false) {
     169        AssertionResult satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool skipUnbound = false) {
    168170                // skip unused assertions
    169                 if ( ! assn.second.isUsed ) return true;
     171                // static unsigned int cnt = 0; // I think this was debugging code so I commented it
     172                if ( ! assn.second.isUsed ) return AssertionResult::Success;
     173
     174                // if (assn.first->var->name[1] == '|') std::cerr << ++cnt << std::endl; // I think this was debugging code so I commented it
    170175
    171176                // find candidates that unify with the desired type
    172                 AssnCandidateList matches;
     177                AssnCandidateList matches, inexactMatches;
    173178
    174179                std::vector<ast::SymbolTable::IdData> candidates;
     
    179184                                .strict_as<ast::FunctionType>()->params[0]
    180185                                .strict_as<ast::ReferenceType>()->base;
    181                         sat.cand->env.apply(thisArgType);
     186                        // sat.cand->env.apply(thisArgType);
     187
     188                        if (auto inst = thisArgType.as<ast::TypeInstType>()) {
     189                                auto cls = sat.cand->env.lookup(*inst);
     190                                if (cls && cls->bound) thisArgType = cls->bound;
     191                        }
    182192
    183193                        std::string otypeKey = "";
    184194                        if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer;
    185195                        else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams);
    186                         else if (skipUnbound) return false;
     196                        else if (skipUnbound) return AssertionResult::Skip;
    187197
    188198                        candidates = sat.symtab.specialLookupId(kind, otypeKey);
     
    212222
    213223                        ast::OpenVarSet closed;
    214                         findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed );
    215                         findOpenVars( adjType, newOpen, closed, newNeed, have, FirstOpen );
    216                         if ( allowConversion ) {
     224                        // findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed );
     225                        findOpenVars( adjType, newOpen, closed, newNeed, have, newEnv, FirstOpen );
     226                        ast::TypeEnvironment tempNewEnv {newEnv};
     227
     228                        if ( unifyExact( toType, adjType, tempNewEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) {
     229                                // set up binding slot for recursive assertions
     230                                ast::UniqueId crntResnSlot = 0;
     231                                if ( ! newNeed.empty() ) {
     232                                        crntResnSlot = ++globalResnSlot;
     233                                        for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
     234                                }
     235
     236                                matches.emplace_back(
     237                                        cdata, adjType, std::move( tempNewEnv ), std::move( have ), std::move( newNeed ),
     238                                        std::move( newOpen ), crntResnSlot );
     239                        }
     240                        else if ( matches.empty() ) {
     241                                // restore invalidated env
     242                                // newEnv = sat.cand->env;
     243                                // newNeed.clear();
    217244                                if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) {
    218245                                        // set up binding slot for recursive assertions
     
    223250                                        }
    224251
    225                                         matches.emplace_back(
     252                                        inexactMatches.emplace_back(
    226253                                                cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    227254                                                std::move( newOpen ), crntResnSlot );
    228255                                }
    229256                        }
    230                         else {
    231                                 if ( unifyExact( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) {
    232                                         // set up binding slot for recursive assertions
    233                                         ast::UniqueId crntResnSlot = 0;
    234                                         if ( ! newNeed.empty() ) {
    235                                                 crntResnSlot = ++globalResnSlot;
    236                                                 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; }
    237                                         }
    238 
    239                                         matches.emplace_back(
    240                                                 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    241                                                 std::move( newOpen ), crntResnSlot );
    242                                 }
    243                         }
    244257                }
    245258
    246259                // break if no satisfying match
    247                 if ( matches.empty() ) return false;
     260                if ( matches.empty() ) matches = std::move(inexactMatches);
     261                if ( matches.empty() ) return AssertionResult::Fail;
    248262
    249263                // defer if too many satisfying matches
    250264                if ( matches.size() > 1 ) {
    251265                        sat.deferred.emplace_back( assn.first, assn.second, std::move( matches ) );
    252                         return true;
     266                        return AssertionResult::Success;
    253267                }
    254268
    255269                // otherwise bind unique match in ongoing scope
    256270                AssnCandidate & match = matches.front();
    257                 addToSymbolTable( match.have, sat.symtab );
     271                // addToSymbolTable( match.have, sat.symtab );
    258272                sat.newNeed.insert( match.need.begin(), match.need.end() );
    259273                sat.cand->env = std::move( match.env );
     
    261275
    262276                bindAssertion( assn.first, assn.second, sat.cand, match, sat.inferred );
    263                 return true;
     277                return AssertionResult::Success;
    264278        }
    265279
     
    438452                // for each current mutually-compatible set of assertions
    439453                for ( SatState & sat : sats ) {
    440                         bool allowConversion = false;
    441454                        // stop this branch if a better option is already found
    442455                        auto it = thresholds.find( pruneKey( *sat.cand ) );
     
    447460                        for (unsigned resetCount = 0; ; ++resetCount) {
    448461                                ast::AssertionList next;
    449                                 resetTyVarRenaming();
    450462                                // make initial pass at matching assertions
    451463                                for ( auto & assn : sat.need ) {
     464                                        resetTyVarRenaming();
    452465                                        // fail early if any assertion is not satisfiable
    453                                         if ( ! satisfyAssertion( assn, sat, allowConversion, !next.empty() ) ) {
    454                                                 next.emplace_back(assn);
    455                                                 // goto nextSat;
    456                                         }
    457                                 }
    458                                 // success
    459                                 if (next.empty()) break;
    460                                 // fail if nothing resolves
    461                                 else if (next.size() == sat.need.size()) {
    462                                         if (allowConversion) {
     466                                        auto result = satisfyAssertion( assn, sat, !next.empty() );
     467                                        if ( result == AssertionResult::Fail ) {
    463468                                                Indenter tabs{ 3 };
    464469                                                std::ostringstream ss;
     
    466471                                                print( ss, *sat.cand, ++tabs );
    467472                                                ss << (tabs-1) << "Could not satisfy assertion:\n";
    468                                                 ast::print( ss, next[0].first, tabs );
     473                                                ast::print( ss, assn.first, tabs );
    469474
    470475                                                errors.emplace_back( ss.str() );
    471476                                                goto nextSat;
    472477                                        }
    473 
    474                                         else {
    475                                                 allowConversion = true;
    476                                                 continue;
    477                                         }
    478                                 }
    479                                 allowConversion = false;
     478                                        else if ( result == AssertionResult::Skip ) {
     479                                                next.emplace_back(assn);
     480                                                // goto nextSat;
     481                                        }
     482                                }
     483                                // success
     484                                if (next.empty()) break;
     485
    480486                                sat.need = std::move(next);
    481487                        }
     
    531537                                                sat.cand->expr, std::move( compat.env ), std::move( compat.open ),
    532538                                                ast::AssertionSet{} /* need moved into satisfaction state */,
    533                                                 sat.cand->cost, sat.cand->cvtCost );
     539                                                sat.cand->cost );
    534540
    535541                                        ast::AssertionSet nextNewNeed{ sat.newNeed };
     
    544550                                        for ( DeferRef r : compat.assns ) {
    545551                                                AssnCandidate match = r.match;
    546                                                 addToSymbolTable( match.have, nextSymtab );
     552                                                // addToSymbolTable( match.have, nextSymtab );
    547553                                                nextNewNeed.insert( match.need.begin(), match.need.end() );
    548554
  • src/ResolvExpr/Unify.cc

    rfa5e1aa5 rb7b3e41  
    160160                env.apply( newSecond );
    161161
    162                 findOpenVars( newFirst, open, closed, need, have, FirstClosed );
    163                 findOpenVars( newSecond, open, closed, need, have, FirstOpen );
     162                // findOpenVars( newFirst, open, closed, need, have, FirstClosed );
     163                findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
    164164
    165165                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
     
    964964                        // check that the other type is compatible and named the same
    965965                        auto otherInst = dynamic_cast< const XInstType * >( other );
    966                         if (otherInst && inst->name == otherInst->name) this->result = otherInst;
     966                        if (otherInst && inst->name == otherInst->name)
     967                                this->result = otherInst;
    967968                        return otherInst;
    968969                }
     
    10491050
    10501051                void postvisit( const ast::TypeInstType * typeInst ) {
    1051                         assert( open.find( *typeInst ) == open.end() );
    1052                         handleRefType( typeInst, type2 );
     1052                        // assert( open.find( *typeInst ) == open.end() );
     1053                        auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
     1054                        if (otherInst && typeInst->name == otherInst->name)
     1055                                this->result = otherInst;
     1056                        // return otherInst;
    10531057                }
    10541058
     
    11611165        ) {
    11621166                ast::OpenVarSet closed;
    1163                 findOpenVars( type1, open, closed, need, have, FirstClosed );
    1164                 findOpenVars( type2, open, closed, need, have, FirstOpen );
     1167                // findOpenVars( type1, open, closed, need, have, FirstClosed );
     1168                findOpenVars( type2, open, closed, need, have, env, FirstOpen );
    11651169                return unifyInexact(
    11661170                        type1, type2, env, need, have, open, WidenMode{ true, true }, common );
     
    11791183                        entry1 = var1 ? open.find( *var1 ) : open.end(),
    11801184                        entry2 = var2 ? open.find( *var2 ) : open.end();
    1181                 bool isopen1 = entry1 != open.end();
    1182                 bool isopen2 = entry2 != open.end();
    1183 
     1185                // bool isopen1 = entry1 != open.end();
     1186                // bool isopen2 = entry2 != open.end();
     1187                bool isopen1 = var1 && env.lookup(*var1);
     1188                bool isopen2 = var2 && env.lookup(*var2);
     1189
     1190                /*
    11841191                if ( isopen1 && isopen2 ) {
    11851192                        if ( entry1->second.kind != entry2->second.kind ) return false;
     
    11901197                        return env.bindVar( var1, type2, entry1->second, need, have, open, widen );
    11911198                } else if ( isopen2 ) {
    1192                         return env.bindVar( var2, type1, entry2->second, need, have, open, widen );
    1193                 } else {
     1199                        return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
     1200                } */
     1201                if ( isopen1 && isopen2 ) {
     1202                        if ( var1->base->kind != var2->base->kind ) return false;
     1203                        return env.bindVarToVar(
     1204                                var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
     1205                                open, widen );
     1206                } else if ( isopen1 ) {
     1207                        return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
     1208                } else if ( isopen2 ) {
     1209                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
     1210                }else {
    11941211                        return ast::Pass<Unify_new>::read(
    11951212                                type1, type2, env, need, have, open, widen );
    11961213                }
     1214               
    11971215        }
    11981216
  • src/SynTree/Expression.cc

    rfa5e1aa5 rb7b3e41  
    267267}
    268268
    269 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
     269CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated, CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) {
    270270        set_result(toType);
    271271}
    272272
    273 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
     273CastExpr::CastExpr( Expression * arg, bool isGenerated, CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) {
    274274        set_result( new VoidType( Type::Qualifiers() ) );
    275275}
    276276
    277 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) {
     277CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ), kind( other.kind ) {
    278278}
    279279
  • src/SynTree/Expression.h

    rfa5e1aa5 rb7b3e41  
    271271        bool isGenerated = true;
    272272
    273         CastExpr( Expression * arg, bool isGenerated = true );
    274         CastExpr( Expression * arg, Type * toType, bool isGenerated = true );
     273        enum CastKind {
     274                Default, // C
     275                Coerce, // reinterpret cast
     276                Return  // overload selection
     277        };
     278
     279        CastKind kind = Default;
     280
     281        CastExpr( Expression * arg, bool isGenerated = true, CastKind kind = Default );
     282        CastExpr( Expression * arg, Type * toType, bool isGenerated = true, CastKind kind = Default );
    275283        CastExpr( Expression * arg, void * ) = delete; // prevent accidentally passing pointers for isGenerated in the first constructor
    276284        CastExpr( const CastExpr & other );
  • src/Tuples/TupleAssignment.cc

    rfa5e1aa5 rb7b3e41  
    679679
    680680                                ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );
     681                                finder.allowVoid = true;
    681682
    682683                                try {
  • src/Validate/Autogen.cpp

    rfa5e1aa5 rb7b3e41  
    321321void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) {
    322322        assert( nullptr != decl->stmts );
     323        assert( decl->type_params.size() == getGenericParams( type ).size() );
    323324
    324325        definitions.push_back( decl );
     
    356357                decl->init = nullptr;
    357358                splice( assertions, decl->assertions );
    358                 oldToNew.emplace( std::make_pair( old_param, decl ) );
     359                oldToNew.emplace( old_param, decl );
    359360                type_params.push_back( decl );
    360361        }
     
    522523        InitTweak::InitExpander_new srcParam( src );
    523524        // Assign to destination.
    524         ast::Expr * dstSelect = new ast::MemberExpr(
     525        ast::MemberExpr * dstSelect = new ast::MemberExpr(
    525526                location,
    526527                field,
     
    574575                }
    575576
    576                 ast::Expr * srcSelect = (srcParam) ? new ast::MemberExpr(
     577                ast::MemberExpr * srcSelect = (srcParam) ? new ast::MemberExpr(
    577578                        location, field, new ast::VariableExpr( location, srcParam )
    578579                ) : nullptr;
  • src/Validate/HoistStruct.cpp

    rfa5e1aa5 rb7b3e41  
    1818#include <sstream>
    1919
     20#include "AST/DeclReplacer.hpp"
    2021#include "AST/Pass.hpp"
    2122#include "AST/TranslationUnit.hpp"
     23#include "AST/Vector.hpp"
    2224
    2325namespace Validate {
     
    5153        template<typename AggrDecl>
    5254        AggrDecl const * postAggregate( AggrDecl const * );
     55        template<typename InstType>
     56        InstType const * preCollectionInstType( InstType const * type );
    5357
    5458        ast::AggregateDecl const * parent = nullptr;
     
    6670        qualifiedName( decl, ss );
    6771        return ss.str();
     72}
     73
     74void extendParams( ast::vector<ast::TypeDecl> & dstParams,
     75                ast::vector<ast::TypeDecl> const & srcParams ) {
     76        if ( srcParams.empty() ) return;
     77
     78        ast::DeclReplacer::TypeMap newToOld;
     79        ast::vector<ast::TypeDecl> params;
     80        for ( ast::ptr<ast::TypeDecl> const & srcParam : srcParams ) {
     81                ast::TypeDecl * dstParam = ast::deepCopy( srcParam.get() );
     82                dstParam->init = nullptr;
     83                newToOld.emplace( srcParam, dstParam );
     84                for ( auto assertion : dstParam->assertions ) {
     85                        assertion = ast::DeclReplacer::replace( assertion, newToOld );
     86                }
     87                params.emplace_back( dstParam );
     88        }
     89        spliceBegin( dstParams, params );
    6890}
    6991
     
    7496                mut->parent = parent;
    7597                mut->name = qualifiedName( mut );
    76                 return mut;
    77         } else {
    78                 GuardValue( parent ) = decl;
    79                 return decl;
    80         }
     98                extendParams( mut->params, parent->params );
     99                decl = mut;
     100        }
     101        GuardValue( parent ) = decl;
     102        return decl;
    81103}
    82104
     
    112134}
    113135
     136ast::AggregateDecl const * commonParent(
     137                ast::AggregateDecl const * lhs, ast::AggregateDecl const * rhs ) {
     138        for ( auto outer = lhs ; outer ; outer = outer->parent ) {
     139                for ( auto inner = rhs ; inner ; inner = inner->parent ) {
     140                        if ( outer == inner ) {
     141                                return outer;
     142                        }
     143                }
     144        }
     145        return nullptr;
     146}
     147
     148template<typename InstType>
     149InstType const * HoistStructCore::preCollectionInstType( InstType const * type ) {
     150    if ( !type->base->parent ) return type;
     151    if ( type->base->params.empty() ) return type;
     152
     153    InstType * mut = ast::mutate( type );
     154    ast::AggregateDecl const * parent =
     155        commonParent( this->parent, mut->base->parent );
     156    assert( parent );
     157
     158    std::vector<ast::ptr<ast::Expr>> args;
     159    for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
     160        args.emplace_back( new ast::TypeExpr( param->location,
     161            new ast::TypeInstType( param )
     162        ) );
     163    }
     164    spliceBegin( mut->params, args );
     165    return mut;
     166}
     167
    114168template<typename InstType>
    115169InstType const * preInstType( InstType const * type ) {
     
    121175
    122176ast::StructInstType const * HoistStructCore::previsit( ast::StructInstType const * type ) {
    123         return preInstType( type );
     177        return preInstType( preCollectionInstType( type ) );
    124178}
    125179
    126180ast::UnionInstType const * HoistStructCore::previsit( ast::UnionInstType const * type ) {
    127         return preInstType( type );
     181        return preInstType( preCollectionInstType( type ) );
    128182}
    129183
  • src/Virtual/VirtualDtor.cpp

    rfa5e1aa5 rb7b3e41  
    146146
    147147            CompoundStmt * dtorBody = mutate( decl->stmts.get() );
    148             // Adds the following to the end of any actor/message dtor:
     148            // Adds the following to the start of any actor/message dtor:
    149149            //  __CFA_dtor_shutdown( this );
    150             dtorBody->push_front( new ExprStmt(
    151                 decl->location,
    152                                 new UntypedExpr (
    153                     decl->location,
    154                                         new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
    155                                         {
    156                         new NameExpr( decl->location, decl->params.at(0)->name )
    157                                         }
    158                                 )
    159                         ));
     150            dtorBody->push_front(
     151                new IfStmt( decl->location,
     152                    new UntypedExpr (
     153                        decl->location,
     154                        new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
     155                        {
     156                            new NameExpr( decl->location, decl->params.at(0)->name )
     157                        }
     158                    ),
     159                    new ReturnStmt( decl->location, nullptr )
     160                )
     161            );
    160162            return;
    161163        }
  • src/main.cc

    rfa5e1aa5 rb7b3e41  
    2828#include <list>                             // for list
    2929#include <string>                           // for char_traits, operator<<
    30 
    31 using namespace std;
    3230
    3331#include "AST/Convert.hpp"
     
    8886#include "Virtual/VirtualDtor.hpp"           // for implementVirtDtors
    8987
     88using namespace std;
     89
    9090static void NewPass( const char * const name ) {
    9191        Stats::Heap::newPass( name );
     
    335335
    336336                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
     337                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
    337338                PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
    338                 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
    339339                PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit );
    340340                PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
Note: See TracChangeset for help on using the changeset viewer.