Changeset 6b224a52 for src/ResolvExpr


Ignore:
Timestamp:
Aug 25, 2017, 12:11:53 PM (9 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, stuck-waitfor-destruct, with_gc
Children:
bf7b9da7
Parents:
135b431 (diff), f676b84 (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/ResolvExpr
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/Alternative.cc

    r135b431 r6b224a52  
    3434                : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( env ) {}
    3535
    36         Alternative::Alternative( const Alternative &other ) {
    37                 initialize( other, *this );
     36        Alternative::Alternative( const Alternative &other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( maybeClone( other.expr ) ), env( other.env ) {
    3837        }
    3938
    4039        Alternative &Alternative::operator=( const Alternative &other ) {
    4140                if ( &other == this ) return *this;
    42                 initialize( other, *this );
     41                delete expr;
     42                cost = other.cost;
     43                cvtCost = other.cvtCost;
     44                expr = maybeClone( other.expr );
     45                env = other.env;
    4346                return *this;
    4447        }
     
    5760                other.expr = nullptr;
    5861                return *this;
    59         }
    60 
    61         void Alternative::initialize( const Alternative &src, Alternative &dest ) {
    62                 dest.cost = src.cost;
    63                 dest.cvtCost = src.cvtCost;
    64                 dest.expr = maybeClone( src.expr );
    65                 dest.env = src.env;
    6662        }
    6763
  • src/ResolvExpr/Alternative.h

    r135b431 r6b224a52  
    3939                ~Alternative();
    4040
    41                 void initialize( const Alternative &src, Alternative &dest );
    42 
    4341                void print( std::ostream &os, int indent = 0 ) const;
    4442
  • src/ResolvExpr/AlternativeFinder.cc

    r135b431 r6b224a52  
    6767
    6868        Cost sumCost( const AltList &in ) {
    69                 Cost total;
     69                Cost total = Cost::zero;
    7070                for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
    7171                        total += i->cost;
     
    144144                        expr->get_result()->accept( global_renamer );
    145145                }
    146         }
     146
     147                void referenceToRvalueConversion( Expression *& expr ) {
     148                        if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
     149                                // cast away reference from expr
     150                                expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
     151                        }
     152                }
     153        } // namespace
    147154
    148155        template< typename InputIterator, typename OutputIterator >
     
    186193                        if ( alternatives.begin() == oldBegin ) {
    187194                                std::ostringstream stream;
    188                                 stream << "Can't choose between " << alternatives.size() << " alternatives for expression ";
     195                                AltList winners;
     196                                findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
     197                                stream << "Can't choose between " << winners.size() << " alternatives for expression ";
    189198                                expr->print( stream );
    190199                                stream << "Alternatives are:";
    191                                 AltList winners;
    192                                 findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
    193200                                printAlts( winners, stream, 8 );
    194201                                throw SemanticError( stream.str() );
     
    213220        void AlternativeFinder::addAnonConversions( const Alternative & alt ) {
    214221                // adds anonymous member interpretations whenever an aggregate value type is seen.
    215                 Expression * expr = alt.expr->clone();
    216                 std::unique_ptr< Expression > manager( expr ); // RAII for expr
    217                 alt.env.apply( expr->get_result() );
    218                 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( expr->get_result() ) ) {
     222                // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
     223                std::unique_ptr<Expression> aggrExpr( alt.expr->clone() );
     224                alt.env.apply( aggrExpr->get_result() );
     225                Type * aggrType = aggrExpr->get_result();
     226                if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
     227                        aggrType = aggrType->stripReferences();
     228                        aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
     229                }
     230
     231                if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
    219232                        NameExpr nameExpr( "" );
    220                         addAggMembers( structInst, expr, alt.cost+Cost( 0, 0, 1 ), alt.env, &nameExpr );
    221                 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( expr->get_result() ) ) {
     233                        addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
     234                } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
    222235                        NameExpr nameExpr( "" );
    223                         addAggMembers( unionInst, expr, alt.cost+Cost( 0, 0, 1 ), alt.env, &nameExpr );
     236                        addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
    224237                } // if
    225238        }
     
    228241        void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
    229242                // by this point, member must be a name expr
    230                 NameExpr * nameExpr = safe_dynamic_cast< NameExpr * >( member );
     243                NameExpr * nameExpr = dynamic_cast< NameExpr * >( member );
     244                if ( ! nameExpr ) return;
    231245                const std::string & name = nameExpr->get_name();
    232246                std::list< Declaration* > members;
     
    250264                        // during parsing and reusing that information here.
    251265                        std::stringstream ss( constantExpr->get_constant()->get_value() );
    252                         int val;
     266                        int val = 0;
    253267                        std::string tmp;
    254268                        if ( ss >> val && ! (ss >> tmp) ) {
     
    272286        }
    273287
    274         Cost computeConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
     288        Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
     289                PRINT(
     290                        std::cerr << std::endl << "converting ";
     291                        actualType->print( std::cerr, 8 );
     292                        std::cerr << std::endl << " to ";
     293                        formalType->print( std::cerr, 8 );
     294                        std::cerr << std::endl << "environment is: ";
     295                        env.print( std::cerr, 8 );
     296                        std::cerr << std::endl;
     297                )
     298                Cost convCost = conversionCost( actualType, formalType, indexer, env );
     299                PRINT(
     300                        std::cerr << std::endl << "cost is" << convCost << std::endl;
     301                )
     302                if ( convCost == Cost::infinity ) {
     303                        return convCost;
     304                }
     305                convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
     306                return convCost;
     307        }
     308
     309        Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
     310                Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
     311                // if ( convCost != Cost::zero ) {
     312
     313                // xxx - temporary -- ignore poly cost, since this causes some polymorphic functions to be cast, which causes the specialize
     314                // pass to try to specialize them, which currently does not work. Once that is fixed, remove the next 3 lines and uncomment the
     315                // previous line.
     316                Cost tmpCost = convCost;
     317                tmpCost.incPoly( -tmpCost.get_polyCost() );
     318                if ( tmpCost != Cost::zero ) {
     319                        Type *newType = formalType->clone();
     320                        env.apply( newType );
     321                        actualExpr = new CastExpr( actualExpr, newType );
     322                        // xxx - SHOULD be able to resolve this cast, but at the moment pointers are not castable to zero_t, but are implicitly convertible. This is clearly
     323                        // inconsistent, once this is fixed it should be possible to resolve the cast.
     324                        // xxx - this isn't working, it appears because type1 (the formal type) is seen as widenable, but it shouldn't be, because this makes the conversion from DT* to DT* since commontype(zero_t, DT*) is DT*, rather than just nothing.
     325
     326                        // AlternativeFinder finder( indexer, env );
     327                        // finder.findWithAdjustment( actualExpr );
     328                        // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." );
     329                        // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." );
     330                        // Alternative & alt = finder.get_alternatives().front();
     331                        // delete actualExpr;
     332                        // actualExpr = alt.expr->clone();
     333                }
     334                return convCost;
     335        }
     336
     337        Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
    275338                ApplicationExpr *appExpr = safe_dynamic_cast< ApplicationExpr* >( alt.expr );
    276339                PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
    277340                FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
    278341
    279                 Cost convCost( 0, 0, 0 );
     342                Cost convCost = Cost::zero;
    280343                std::list< DeclarationWithType* >& formals = function->get_parameters();
    281344                std::list< DeclarationWithType* >::iterator formal = formals.begin();
     
    290353                                actualType->print( std::cerr, 8 );
    291354                        )
    292                         Cost actualCost;
    293355                        if ( formal == formals.end() ) {
    294356                                if ( function->get_isVarArgs() ) {
    295                                         convCost += Cost( 1, 0, 0 );
     357                                        convCost.incUnsafe();
     358                                        // convert reference-typed expressions to value-typed expressions
     359                                        referenceToRvalueConversion( *actualExpr );
    296360                                        continue;
    297361                                } else {
     
    305369                                std::cerr << std::endl << " to ";
    306370                                formalType->print( std::cerr, 8 );
     371                                std::cerr << std::endl << "environment is: ";
     372                                alt.env.print( std::cerr, 8 );
     373                                std::cerr << std::endl;
    307374                        )
    308                         Cost newCost = conversionCost( actualType, formalType, indexer, alt.env );
    309                         PRINT(
    310                                 std::cerr << std::endl << "cost is" << newCost << std::endl;
    311                         )
    312 
    313                         if ( newCost == Cost::infinity ) {
    314                                 return newCost;
    315                         }
    316                         convCost += newCost;
    317                         actualCost += newCost;
    318                         if ( actualCost != Cost( 0, 0, 0 ) ) {
    319                                 Type *newType = formalType->clone();
    320                                 alt.env.apply( newType );
    321                                 *actualExpr = new CastExpr( *actualExpr, newType );
    322                         }
    323                         convCost += Cost( 0, polyCost( formalType, alt.env, indexer ) + polyCost( actualType, alt.env, indexer ), 0 );
     375                        convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
    324376                        ++formal; // can't be in for-loop update because of the continue
    325377                }
     
    329381
    330382                for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
    331                         PRINT(
    332                                 std::cerr << std::endl << "converting ";
    333                                 assert->second.actualType->print( std::cerr, 8 );
    334                                 std::cerr << std::endl << " to ";
    335                                 assert->second.formalType->print( std::cerr, 8 );
    336                         )
    337                         Cost newCost = conversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
    338                         PRINT(
    339                                 std::cerr << std::endl << "cost of conversion is " << newCost << std::endl;
    340                         )
    341                         if ( newCost == Cost::infinity ) {
    342                                 return newCost;
    343                         }
    344                         convCost += newCost;
    345                         convCost += Cost( 0, polyCost( assert->second.formalType, alt.env, indexer ) + polyCost( assert->second.actualType, alt.env, indexer ), 0 );
     383                        convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
    346384                }
    347385
     
    400438                        Expression * actual = actualIt->expr;
    401439                        Type * actualType = actual->get_result();
     440
    402441                        PRINT(
    403442                                std::cerr << "formal type is ";
     
    408447                        )
    409448                        if ( ! unify( formalType, actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
     449                                // std::cerr << "unify failed" << std::endl;
    410450                                return false;
    411451                        }
     
    452492                        // match flattened actuals with formal parameters - actuals will be grouped to match
    453493                        // with formals as appropriate
    454                         Cost cost;
     494                        Cost cost = Cost::zero;
    455495                        std::list< Expression * > newExprs;
    456496                        ObjectDecl * obj = safe_dynamic_cast< ObjectDecl * >( formal );
     
    613653                AssertionSet newNeed;
    614654                //AssertionParentSet needParents;
     655                PRINT(
     656                        std::cerr << "env is: " << std::endl;
     657                        newAlt.env.print( std::cerr, 0 );
     658                        std::cerr << std::endl;
     659                )
     660
    615661                inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out );
    616662//      PRINT(
     
    643689                        makeExprList( instantiatedActuals, appExpr->get_args() );
    644690                        PRINT(
     691                                std::cerr << "instantiate function success: " << appExpr << std::endl;
    645692                                std::cerr << "need assertions:" << std::endl;
    646693                                printAssertionSet( resultNeed, std::cerr, 8 );
     
    663710                                UntypedExpr *vexpr = untypedExpr->clone();
    664711                                vexpr->set_result( pt.clone() );
    665                                 alternatives.push_back( Alternative( vexpr, env, Cost()) );
     712                                alternatives.push_back( Alternative( vexpr, env, Cost::zero) );
    666713                                return;
    667714                        }
     
    681728                AltList candidates;
    682729                SemanticError errors;
    683                 for ( AltList::const_iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
     730                for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
    684731                        try {
    685732                                PRINT(
     
    688735                                )
    689736                                // check if the type is pointer to function
    690                                 PointerType *pointer;
    691                                 if ( ( pointer = dynamic_cast< PointerType* >( func->expr->get_result() ) ) ) {
     737                                if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
    692738                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
     739                                                referenceToRvalueConversion( func->expr );
    693740                                                for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
    694741                                                        // XXX
     
    696743                                                        makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
    697744                                                }
    698                                         } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( pointer->get_base() ) ) {
    699                                                 EqvClass eqvClass;
    700                                                 if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
    701                                                         if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
    702                                                                 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
    703                                                                         makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
    704                                                                 } // for
    705                                                         } // if
     745                                        }
     746                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
     747                                        referenceToRvalueConversion( func->expr );
     748                                        EqvClass eqvClass;
     749                                        if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
     750                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
     751                                                        for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
     752                                                                makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
     753                                                        } // for
    706754                                                } // if
    707755                                        } // if
     
    722770                                        }
    723771
    724                                         for ( AltList::const_iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
     772                                        for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
    725773                                                // check if the type is pointer to function
    726                                                 PointerType *pointer;
    727                                                 if ( ( pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result() ) ) ) {
     774                                                if ( PointerType *pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result()->stripReferences() ) ) {
    728775                                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
     776                                                                referenceToRvalueConversion( funcOp->expr );
    729777                                                                for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
    730778                                                                        AltList currentAlt;
     
    747795                // compute conversionsion costs
    748796                for ( AltList::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc ) {
    749                         Cost cvtCost = computeConversionCost( *withFunc, indexer );
     797                        Cost cvtCost = computeApplicationConversionCost( *withFunc, indexer );
    750798
    751799                        PRINT(
     
    753801                                PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
    754802                                FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
    755                                 std::cerr << "Case +++++++++++++" << std::endl;
     803                                std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
    756804                                std::cerr << "formals are:" << std::endl;
    757805                                printAll( function->get_parameters(), std::cerr, 8 );
     
    796844        bool isLvalue( Expression *expr ) {
    797845                // xxx - recurse into tuples?
    798                 return expr->has_result() && expr->get_result()->get_lvalue();
     846                return expr->has_result() && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
    799847        }
    800848
     
    810858
    811859        Expression * restructureCast( Expression * argExpr, Type * toType ) {
    812                 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() ) {
    813                         // Argument expression is a tuple and the target type is not void. Cast each member of the tuple
    814                         // to its corresponding target type, producing the tuple of those cast expressions. If there are
    815                         // more components of the tuple than components in the target type, then excess components do not
    816                         // come out in the result expression (but UniqueExprs ensure that side effects will still be done).
    817                         if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) {
     860                if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
     861                        // Argument expression is a tuple and the target type is not void and not a reference type.
     862                        // Cast each member of the tuple to its corresponding target type, producing the tuple of those
     863                        // cast expressions. If there are more components of the tuple than components in the target type,
     864                        // then excess components do not come out in the result expression (but UniqueExprs ensure that
     865                        // side effects will still be done).
     866                        if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
    818867                                // expressions which may contain side effects require a single unique instance of the expression.
    819868                                argExpr = new UniqueExpr( argExpr );
     
    855904                        // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
    856905                        // to.
    857                         int discardedValues = (*i).expr->get_result()->size() - castExpr->get_result()->size();
     906                        int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size();
    858907                        if ( discardedValues < 0 ) continue;
    859908                        // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
    860909                        // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
    861910                        // unification run for side-effects
    862                         unify( castExpr->get_result(), (*i).expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
    863                         Cost thisCost = castCost( (*i).expr->get_result(), castExpr->get_result(), indexer, i->env );
     911                        unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
     912                        Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env );
    864913                        if ( thisCost != Cost::infinity ) {
    865914                                // count one safe conversion for each value that is thrown away
    866                                 thisCost += Cost( 0, 0, discardedValues );
    867 
    868                                 candidates.push_back( Alternative( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost ) );
     915                                thisCost.incSafe( discardedValues );
     916                                Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost );
     917                                // xxx - this doesn't work at the moment, since inferParameters requires an ApplicationExpr as the alternative.
     918                                // Once this works, it should be possible to infer parameters on a cast expression and specialize any function.
     919
     920                                // inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
     921                                candidates.emplace_back( std::move( newAlt ) );
    869922                        } // if
    870923                } // for
     
    895948                funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
    896949                for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
    897                         if ( StructInstType *structInst = dynamic_cast< StructInstType* >( agg->expr->get_result() ) ) {
    898                                 addAggMembers( structInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
    899                         } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( agg->expr->get_result() ) ) {
    900                                 addAggMembers( unionInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
    901                         } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( agg->expr->get_result() ) ) {
    902                                 addTupleMembers( tupleType, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
     950                        // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
     951                        std::unique_ptr<Expression> aggrExpr( agg->expr->clone() );
     952                        Type * aggrType = aggrExpr->get_result();
     953                        if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
     954                                aggrType = aggrType->stripReferences();
     955                                aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
     956                        }
     957                        // find member of the given type
     958                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
     959                                addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
     960                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
     961                                addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
     962                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
     963                                addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
    903964                        } // if
    904965                } // for
     
    915976                for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
    916977                        VariableExpr newExpr( *i, nameExpr->get_argName() );
    917                         alternatives.push_back( Alternative( newExpr.clone(), env, Cost() ) );
     978                        alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
    918979                        PRINT(
    919980                                std::cerr << "decl is ";
     
    9551016                        // return the lowest cost alternative for the argument
    9561017                        Alternative &choice = winners.front();
     1018                        referenceToRvalueConversion( choice.expr );
    9571019                        alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
    9581020                } // if
     
    9751037                        // return the lowest cost alternative for the argument
    9761038                        Alternative &choice = winners.front();
     1039                        referenceToRvalueConversion( choice.expr );
    9771040                        alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
    9781041                } // if
     
    10591122                        for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
    10601123                                VariableExpr newExpr( *i );
    1061                                 alternatives.push_back( Alternative( newExpr.clone(), env, Cost() ) );
     1124                                alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
    10621125                                renameTypes( alternatives.back().expr );
    10631126                        } // for
     
    10991162                                                ConditionalExpr *newExpr = new ConditionalExpr( first->expr->clone(), second->expr->clone(), third->expr->clone() );
    11001163                                                newExpr->set_result( commonType ? commonType : second->expr->get_result()->clone() );
     1164                                                // convert both options to the conditional result type
     1165                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
     1166                                                newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
    11011167                                                newAlt.expr = newExpr;
    11021168                                                inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
     
    12321298                                if ( thisCost != Cost::infinity ) {
    12331299                                        // count one safe conversion for each value that is thrown away
    1234                                         thisCost += Cost( 0, 0, discardedValues );
     1300                                        thisCost.incSafe( discardedValues );
    12351301                                        candidates.push_back( Alternative( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ) );
    12361302                                }
  • src/ResolvExpr/CastCost.cc

    r135b431 r6b224a52  
    4949                                assert( type );
    5050                                if ( type->get_base() ) {
    51                                         return castCost( src, type->get_base(), indexer, env ) + Cost( 0, 0, 1 );
     51                                        return castCost( src, type->get_base(), indexer, env ) + Cost::safe;
    5252                                } // if
    5353                        } // if
    5454                } // if
    5555                if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    56                         return Cost( 0, 0, 0 );
     56                        return Cost::zero;
    5757                } else if ( dynamic_cast< VoidType* >( dest ) ) {
    58                         return Cost( 0, 0, 1 );
     58                        return Cost::safe;
     59                } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
     60                        return convertToReferenceCost( src, refType, indexer, env );
    5961                } else {
    6062                        CastCost converter( dest, indexer, env );
     
    6466                        } else {
    6567                                // xxx - why are we adding cost 0 here?
    66                                 return converter.get_cost() + Cost( 0, 0, 0 );
     68                                return converter.get_cost() + Cost::zero;
    6769                        } // if
    6870                } // if
     
    7779                if ( destAsPointer && basicType->isInteger() ) {
    7880                        // necessary for, e.g. unsigned long => void*
    79                         cost = Cost( 1, 0, 0 );
     81                        cost = Cost::unsafe;
    8082                } else {
    81                         ConversionCost::visit( basicType );
     83                        cost = conversionCost( basicType, dest, indexer, env );
    8284                } // if
    8385        }
     
    8688                if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    8789                        if ( pointerType->get_qualifiers() <= destAsPtr->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
    88                                 cost = Cost( 0, 0, 1 );
     90                                cost = Cost::safe;
    8991                        } else {
    9092                                TypeEnvironment newEnv( env );
     
    9395                                int castResult = ptrsCastable( pointerType->get_base(), destAsPtr->get_base(), newEnv, indexer );
    9496                                if ( castResult > 0 ) {
    95                                         cost = Cost( 0, 0, 1 );
     97                                        cost = Cost::safe;
    9698                                } else if ( castResult < 0 ) {
    9799                                        cost = Cost::infinity;
     
    101103                        if ( destAsBasic->isInteger() ) {
    102104                                // necessary for, e.g. void* => unsigned long
    103                                 cost = Cost( 1, 0, 0 );
     105                                cost = Cost::unsafe;
    104106                        } // if
    105107                }
  • src/ResolvExpr/CommonType.cc

    r135b431 r6b224a52  
    2626#include "typeops.h"                     // for isFtype
    2727
    28 
    29 /// #define DEBUG
     28// #define DEBUG
    3029
    3130namespace ResolvExpr {
     
    3938                virtual void visit( PointerType *pointerType );
    4039                virtual void visit( ArrayType *arrayType );
     40                virtual void visit( ReferenceType *refType );
    4141                virtual void visit( FunctionType *functionType );
    4242                virtual void visit( StructInstType *aggregateUseType );
     
    5050                virtual void visit( OneType *oneType );
    5151
    52                 void getCommonWithVoidPointer( PointerType* voidPointer, PointerType* otherPointer );
     52                template< typename Pointer > void getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer );
     53                template< typename RefType > void handleRefType( RefType *inst, Type *other );
    5354
    5455                Type *result;
     
    6061        };
    6162
     63        Type * handleReference( ReferenceType * refType, Type * other, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {
     64                Type * result = nullptr, * common = nullptr;
     65                AssertionSet have, need;
     66                OpenVarSet newOpen( openVars );
     67                // need unify to bind type variables
     68                if ( unify( refType->get_base(), other, env, have, need, newOpen, indexer, common ) ) {
     69                        // std::cerr << "unify success" << std::endl;
     70                        if ( widenSecond ) {
     71                                // std::cerr << "widen second" << std::endl;
     72                                if ( widenFirst || other->get_qualifiers() <= refType->get_qualifiers() ) {
     73                                        result = new ReferenceType( refType->get_qualifiers(), common ); // refType->clone();
     74                                        result->get_qualifiers() |= other->get_qualifiers();
     75                                }
     76                        } else if ( widenFirst ) {
     77                                // std::cerr << "widen first" << std::endl;
     78                                if ( widenSecond || refType->get_qualifiers() <= other->get_qualifiers() ) {
     79                                        result = common;
     80                                        result->get_qualifiers() |= refType->get_qualifiers();
     81                                }
     82                        }
     83                } else {
     84                        // std::cerr << "exact unify failed: " << refType << " " << other << std::endl;
     85                }
     86                // std::cerr << "common type of reference [" << refType << "] and non-reference [" << other << "] is [" << result << "]" << std::endl;
     87                return result;
     88        }
     89
    6290        Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
    6391                CommonType visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
     92
     93                int depth1 = type1->referenceDepth();
     94                int depth2 = type2->referenceDepth();
     95                if ( depth1 > 0 || depth2 > 0 ) {
     96                        int diff = depth1-depth2;
     97                        // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.
     98                        if ( diff > 1 || diff < -1 ) return nullptr;
     99
     100                        // special case where one type has a reference depth of 1 larger than the other
     101                        if ( diff > 0 ) {
     102                                return handleReference( safe_dynamic_cast<ReferenceType *>( type1 ), type2, widenFirst, widenSecond, indexer, env, openVars );
     103                        } else if ( diff < 0 ) {
     104                                return handleReference( safe_dynamic_cast<ReferenceType *>( type2 ), type1, widenSecond, widenFirst, indexer, env, openVars );
     105                        }
     106                        // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.
     107                }
     108
    64109                type1->accept( visitor );
    65110                Type *result = visitor.get_result();
     
    88133                } // if
    89134#ifdef DEBUG
    90                 std::cout << "============= commonType" << std::endl << "type1 is ";
    91                 type1->print( std::cout );
    92                 std::cout << " type2 is ";
    93                 type2->print( std::cout );
     135                std::cerr << "============= commonType" << std::endl << "type1 is ";
     136                type1->print( std::cerr );
     137                std::cerr << " type2 is ";
     138                type2->print( std::cerr );
    94139                if ( result ) {
    95                         std::cout << " common type is ";
    96                         result->print( std::cout );
     140                        std::cerr << " common type is ";
     141                        result->print( std::cerr );
    97142                } else {
    98                         std::cout << " no common type";
    99                 } // if
    100                 std::cout << std::endl;
     143                        std::cerr << " no common type";
     144                } // if
     145                std::cerr << std::endl;
    101146#endif
    102147                return result;
     
    150195        }
    151196
    152         void CommonType::getCommonWithVoidPointer( PointerType* voidPointer, PointerType* otherPointer ) {
     197        template< typename Pointer >
     198        void CommonType::getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer ) {
    153199                if ( TypeInstType* var = dynamic_cast< TypeInstType* >( otherPointer->get_base() ) ) {
    154200                        OpenVarSet::const_iterator entry = openVars.find( var->get_name() );
     
    165211        void CommonType::visit( PointerType *pointerType ) {
    166212                if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
     213                        // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
    167214                        if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
    168215                                getCommonWithVoidPointer( otherPointer, pointerType );
     
    171218                        } else if ( ( pointerType->get_base()->get_qualifiers() >= otherPointer->get_base()->get_qualifiers() || widenFirst )
    172219                                           && ( pointerType->get_base()->get_qualifiers() <= otherPointer->get_base()->get_qualifiers() || widenSecond ) ) {
     220                                // std::cerr << "middle case" << std::endl;
    173221                                Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers(), tq2 = otherPointer->get_base()->get_qualifiers();
    174222                                pointerType->get_base()->get_qualifiers() = Type::Qualifiers();
     
    177225                                OpenVarSet newOpen( openVars );
    178226                                if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) {
     227                                        // std::cerr << "unifyExact success" << std::endl;
    179228                                        if ( tq1 < tq2 ) {
    180229                                                result = pointerType->clone();
     
    184233                                        result->get_qualifiers() = tq1 | tq2;
    185234                                } else {
    186                                         /// std::cout << "place for ptr-to-type" << std::endl;
     235                                        /// std::cerr << "place for ptr-to-type" << std::endl;
    187236                                } // if
    188237                                pointerType->get_base()->get_qualifiers() = tq1;
     
    196245
    197246        void CommonType::visit( __attribute((unused)) ArrayType *arrayType ) {}
     247
     248        void CommonType::visit( ReferenceType *refType ) {
     249                if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
     250                        // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
     251                        // std::cerr << ( refType->get_base()->get_qualifiers() >= otherRef->get_base()->get_qualifiers() || widenFirst ) << (refType->get_base()->get_qualifiers() <= otherRef->get_base()->get_qualifiers() || widenSecond) << std::endl;
     252                        if ( widenFirst && dynamic_cast< VoidType* >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
     253                                getCommonWithVoidPointer( otherRef, refType );
     254                        } else if ( widenSecond && dynamic_cast< VoidType* >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
     255                                getCommonWithVoidPointer( refType, otherRef );
     256                        } else if ( ( refType->get_base()->get_qualifiers() >= otherRef->get_base()->get_qualifiers() || widenFirst )
     257                                           && ( refType->get_base()->get_qualifiers() <= otherRef->get_base()->get_qualifiers() || widenSecond ) ) {
     258                                // std::cerr << "middle case" << std::endl;
     259                                Type::Qualifiers tq1 = refType->get_base()->get_qualifiers(), tq2 = otherRef->get_base()->get_qualifiers();
     260                                refType->get_base()->get_qualifiers() = Type::Qualifiers();
     261                                otherRef->get_base()->get_qualifiers() = Type::Qualifiers();
     262                                AssertionSet have, need;
     263                                OpenVarSet newOpen( openVars );
     264                                if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {
     265                                        if ( tq1 < tq2 ) {
     266                                                result = refType->clone();
     267                                        } else {
     268                                                result = otherRef->clone();
     269                                        } // if
     270                                        result->get_qualifiers() = tq1 | tq2;
     271                                } else {
     272                                        /// std::cerr << "place for ptr-to-type" << std::endl;
     273                                } // if
     274                                refType->get_base()->get_qualifiers() = tq1;
     275                                otherRef->get_base()->get_qualifiers() = tq2;
     276                        } // if
     277                } else if ( widenSecond && dynamic_cast< ZeroType* >( type2 ) ) {
     278                        result = refType->clone();
     279                        result->get_qualifiers() |= type2->get_qualifiers();
     280                } // if
     281        }
     282
    198283        void CommonType::visit( __attribute((unused)) FunctionType *functionType ) {}
    199284        void CommonType::visit( __attribute((unused)) StructInstType *aggregateUseType ) {}
     
    203288                if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
    204289                        // reuse BasicType, EnumInstType code by swapping type2 with enumInstType
    205                         Type * temp = type2;
     290                        ValueGuard< Type * > temp( type2 );
    206291                        type2 = enumInstType;
    207                         temp->accept( *this );
    208                         type2 = temp;
     292                        temp.old->accept( *this );
    209293                } // if
    210294        }
  • src/ResolvExpr/ConversionCost.cc

    r135b431 r6b224a52  
    2828
    2929namespace ResolvExpr {
    30         const Cost Cost::zero = Cost( 0, 0, 0 );
    31         const Cost Cost::infinity = Cost( -1, -1, -1 );
     30        const Cost Cost::zero = Cost( 0, 0, 0, 0 );
     31        const Cost Cost::infinity = Cost( -1, -1, -1, -1 );
     32        const Cost Cost::unsafe = Cost( 1, 0, 0, 0 );
     33        const Cost Cost::poly = Cost( 0, 1, 0, 0 );
     34        const Cost Cost::safe = Cost( 0, 0, 1, 0 );
     35        const Cost Cost::reference = Cost( 0, 0, 0, 1 );
     36
     37#if 0
     38#define PRINT(x) x
     39#else
     40#define PRINT(x)
     41#endif
    3242
    3343        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     
    3545                        EqvClass eqvClass;
    3646                        NamedTypeDecl *namedType;
    37 ///     std::cout << "type inst " << destAsTypeInst->get_name();
     47                        PRINT( std::cerr << "type inst " << destAsTypeInst->get_name(); )
    3848                        if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) {
    3949                                if ( eqvClass.type ) {
     
    4353                                }
    4454                        } else if ( ( namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) ) {
    45 ///       std::cout << " found" << std::endl;
     55                                PRINT( std::cerr << " found" << std::endl; )
    4656                                TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
    4757                                // all typedefs should be gone by this point
    4858                                assert( type );
    4959                                if ( type->get_base() ) {
    50                                         return conversionCost( src, type->get_base(), indexer, env ) + Cost( 0, 0, 1 );
     60                                        return conversionCost( src, type->get_base(), indexer, env ) + Cost::safe;
    5161                                } // if
    5262                        } // if
    53 ///     std::cout << " not found" << std::endl;
    54                 } // if
    55 ///   std::cout << "src is ";
    56 ///   src->print( std::cout );
    57 ///   std::cout << std::endl << "dest is ";
    58 ///   dest->print( std::cout );
    59 ///   std::cout << std::endl << "env is" << std::endl;
    60 ///   env.print( std::cout, 8 );
     63                        PRINT( std::cerr << " not found" << std::endl; )
     64                } // if
     65                PRINT(
     66                        std::cerr << "src is ";
     67                        src->print( std::cerr );
     68                        std::cerr << std::endl << "dest is ";
     69                        dest->print( std::cerr );
     70                        std::cerr << std::endl << "env is" << std::endl;
     71                        env.print( std::cerr, 8 );
     72                )
    6173                if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    62 ///     std::cout << "compatible!" << std::endl;
    63                         return Cost( 0, 0, 0 );
     74                        PRINT( std::cerr << "compatible!" << std::endl; )
     75                        return Cost::zero;
    6476                } else if ( dynamic_cast< VoidType* >( dest ) ) {
    65                         return Cost( 0, 0, 1 );
     77                        return Cost::safe;
     78                } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
     79                        PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
     80                        return convertToReferenceCost( src, refType, indexer, env );
    6681                } else {
    6782                        ConversionCost converter( dest, indexer, env );
     
    7085                                return Cost::infinity;
    7186                        } else {
    72                                 return converter.get_cost() + Cost( 0, 0, 0 );
    73                         } // if
    74                 } // if
     87                                return converter.get_cost() + Cost::zero;
     88                        } // if
     89                } // if
     90        }
     91
     92        Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     93                PRINT( std::cerr << "convert to reference cost..." << std::endl; )
     94                if ( diff > 0 ) {
     95                        // TODO: document this
     96                        Cost cost = convertToReferenceCost( safe_dynamic_cast< ReferenceType * >( src )->get_base(), dest, diff-1, indexer, env );
     97                        cost.incReference();
     98                        return cost;
     99                } else if ( diff < -1 ) {
     100                        // TODO: document this
     101                        Cost cost = convertToReferenceCost( src, safe_dynamic_cast< ReferenceType * >( dest )->get_base(), diff+1, indexer, env );
     102                        cost.incReference();
     103                        return cost;
     104                } else if ( diff == 0 ) {
     105                        ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
     106                        ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
     107                        if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
     108                                PRINT( std::cerr << "converting between references" << std::endl; )
     109                                if ( srcAsRef->get_base()->get_qualifiers() <= destAsRef->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
     110                                        return Cost::safe;
     111                                } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
     112                                        int assignResult = ptrsAssignable( srcAsRef->get_base(), destAsRef->get_base(), env );
     113                                        PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
     114                                        if ( assignResult < 0 ) {
     115                                                return Cost::safe;
     116                                        } else if ( assignResult > 0 ) {
     117                                                return Cost::unsafe;
     118                                        } // if
     119                                } // if
     120                        } else {
     121                                PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
     122                                ConversionCost converter( dest, indexer, env );
     123                                src->accept( converter );
     124                                return converter.get_cost();
     125                        } // if
     126                } else {
     127                        ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
     128                        assert( diff == -1 && destAsRef );
     129                        if ( typesCompatibleIgnoreQualifiers( src, destAsRef->get_base(), indexer, env ) ) {
     130                                PRINT( std::cerr << "converting compatible base type" << std::endl; )
     131                                if ( src->get_lvalue() ) {
     132                                        PRINT(
     133                                                std::cerr << "lvalue to reference conversion" << std::endl;
     134                                                std::cerr << src << " => " << destAsRef << std::endl;
     135                                        )
     136                                        // lvalue-to-reference conversion:  cv lvalue T => cv T &
     137                                        if ( src->get_qualifiers() == destAsRef->get_base()->get_qualifiers() ) {
     138                                                return Cost::reference; // cost needs to be non-zero to add cast
     139                                        } if ( src->get_qualifiers() < destAsRef->get_base()->get_qualifiers() ) {
     140                                                return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
     141                                        } else {
     142                                                return Cost::unsafe;
     143                                        } // if
     144                                } else if ( destAsRef->get_base()->get_const() ) {
     145                                        PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
     146                                        // rvalue-to-const-reference conversion: T => const T &
     147                                        return Cost::safe;
     148                                } else {
     149                                        PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
     150                                        // rvalue-to-reference conversion: T => T &
     151                                        return Cost::unsafe;
     152                                } // if
     153                        } // if
     154                        PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
     155                }
     156                return Cost::infinity;
     157        }
     158
     159        Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     160                int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
     161                return convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env );
    75162        }
    76163
     
    164251                        int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
    165252                        if ( tableResult == -1 ) {
    166                                 cost = Cost( 1, 0, 0 );
    167                         } else {
    168                                 cost = Cost( 0, 0, tableResult );
     253                                cost = Cost::unsafe;
     254                        } else {
     255                                cost = Cost::zero;
     256                                cost.incSafe( tableResult );
    169257                        } // if
    170258                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
    171259                        // xxx - not positive this is correct, but appears to allow casting int => enum
    172                         cost = Cost( 1, 0, 0 );
     260                        cost = Cost::unsafe;
    173261                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    174                         cost = Cost( 1, 0, 0 );
     262                        cost = Cost::unsafe;
    175263                } // if
    176264        }
     
    178266        void ConversionCost::visit(PointerType *pointerType) {
    179267                if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    180                         if ( pointerType->get_base()->get_qualifiers() <= destAsPtr->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
    181                                 cost = Cost( 0, 0, 1 );
    182                         } else {
     268                        PRINT( std::cerr << pointerType << " ===> " << destAsPtr; )
     269                        Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers();
     270                        Type::Qualifiers tq2 = destAsPtr->get_base()->get_qualifiers();
     271                        if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
     272                                if ( tq1 == tq2 ) {
     273                                        // types are the same
     274                                        cost = Cost::zero;
     275                                } else {
     276                                        // types are the same, except otherPointer has more qualifiers
     277                                        PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
     278                                        cost = Cost::safe;
     279                                }
     280                        } else {  // xxx - this discards qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    183281                                int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
    184                                 if ( assignResult < 0 ) {
    185                                         cost = Cost( 0, 0, 1 );
     282                                PRINT( std::cerr << " :: " << assignResult << std::endl; )
     283                                if ( assignResult < 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
     284                                        cost = Cost::safe;
    186285                                } else if ( assignResult > 0 ) {
    187                                         cost = Cost( 1, 0, 0 );
     286                                        cost = Cost::unsafe;
    188287                                } // if
     288                                // assignResult == 0 means Cost::Infinity
    189289                        } // if
    190290                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    191                         cost = Cost( 1, 0, 0 );
     291                        cost = Cost::unsafe;
    192292                } // if
    193293        }
    194294
    195295        void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
     296
     297        void ConversionCost::visit(ReferenceType *refType) {
     298                // Note: dest can never be a reference, since it would have been caught in an earlier check
     299                assert( ! dynamic_cast< ReferenceType * >( dest ) );
     300                // convert reference to rvalue: cv T1 & => T2
     301                // recursively compute conversion cost from T1 to T2.
     302                // cv can be safely dropped because of 'implicit dereference' behavior.
     303                refType->get_base()->accept( *this );
     304                if ( refType->get_base()->get_qualifiers() == dest->get_qualifiers() ) {
     305                        cost.incReference();  // prefer exact qualifiers
     306                } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {
     307                        cost.incSafe(); // then gaining qualifiers
     308                } else {
     309                        cost.incUnsafe(); // lose qualifiers as last resort
     310                }
     311                PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
     312        }
     313
    196314        void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
    197315
     
    215333                static Type::Qualifiers q;
    216334                static BasicType integer( q, BasicType::SignedInt );
    217                 integer.accept( *this );
    218                 if ( cost < Cost( 1, 0, 0 ) ) {
     335                integer.accept( *this );  // safe if dest >= int
     336                if ( cost < Cost::unsafe ) {
    219337                        cost.incSafe();
    220338                } // if
     
    238356                        assert( type );
    239357                        if ( type->get_base() ) {
    240                                 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost( 0, 0, 1 );
     358                                cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
    241359                        } // if
    242360                } // if
     
    244362
    245363        void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
    246                 Cost c;
     364                Cost c = Cost::zero;
    247365                if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
    248366                        std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
     
    276394                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    277395                        if ( tableResult == -1 ) {
    278                                 cost = Cost( 1, 0, 0 );
    279                         } else {
    280                                 cost = Cost( 0, 0, tableResult + 1 );
     396                                cost = Cost::unsafe;
     397                        } else {
     398                                cost = Cost::zero;
     399                                cost.incSafe( tableResult + 1 );
    281400                        }
    282401                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    283                         cost = Cost( 0, 0, 1 );
     402                        cost = Cost::safe;
    284403                }
    285404        }
     
    292411                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    293412                        if ( tableResult == -1 ) {
    294                                 cost = Cost( 1, 0, 0 );
    295                         } else {
    296                                 cost = Cost( 0, 0, tableResult + 1 );
     413                                cost = Cost::unsafe;
     414                        } else {
     415                                cost = Cost::zero;
     416                                cost.incSafe( tableResult + 1 );
    297417                        }
    298418                }
  • src/ResolvExpr/ConversionCost.h

    r135b431 r6b224a52  
    3737                virtual void visit(PointerType *pointerType);
    3838                virtual void visit(ArrayType *arrayType);
     39                virtual void visit(ReferenceType *refType);
    3940                virtual void visit(FunctionType *functionType);
    4041                virtual void visit(StructInstType *aggregateUseType);
     
    5354                const TypeEnvironment &env;
    5455        };
     56
     57        Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    5558} // namespace ResolvExpr
    5659
  • src/ResolvExpr/Cost.h

    r135b431 r6b224a52  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Cost.h -- 
     7// Cost.h --
    88//
    99// Author           : Richard C. Bilson
     
    2020namespace ResolvExpr {
    2121        class Cost {
     22          private:
     23                Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost );
     24
    2225          public:
    23                 Cost();
    24                 Cost( int unsafe, int poly, int safe );
    25  
    26                 void incUnsafe( int inc = 1 );
    27                 void incPoly( int inc = 1 );
    28                 void incSafe( int inc = 1 );
    29  
     26                Cost & incUnsafe( int inc = 1 );
     27                Cost & incPoly( int inc = 1 );
     28                Cost & incSafe( int inc = 1 );
     29                Cost & incReference( int inc = 1 );
     30
     31                int get_unsafeCost() const { return unsafeCost; }
     32                int get_polyCost() const { return polyCost; }
     33                int get_safeCost() const { return safeCost; }
     34                int get_referenceCost() const { return referenceCost; }
     35
    3036                Cost operator+( const Cost &other ) const;
    3137                Cost operator-( const Cost &other ) const;
     
    3541                bool operator!=( const Cost &other ) const;
    3642                friend std::ostream &operator<<( std::ostream &os, const Cost &cost );
    37  
     43
    3844                static const Cost zero;
    3945                static const Cost infinity;
     46
     47                static const Cost unsafe;
     48                static const Cost poly;
     49                static const Cost safe;
     50                static const Cost reference;
    4051          private:
    4152                int compare( const Cost &other ) const;
    4253
    43                 int unsafe;
    44                 int poly;
    45                 int safe;
     54                int unsafeCost;
     55                int polyCost;
     56                int safeCost;
     57                int referenceCost;
    4658        };
    4759
    48         inline Cost::Cost() : unsafe( 0 ), poly( 0 ), safe( 0 ) {}
     60        inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), referenceCost( referenceCost ) {}
    4961
    50         inline Cost::Cost( int unsafe, int poly, int safe ) : unsafe( unsafe ), poly( poly ), safe( safe ) {}
    51 
    52         inline void Cost::incUnsafe( int inc ) {
    53                 unsafe += inc;
     62        inline Cost & Cost::incUnsafe( int inc ) {
     63                if ( *this == infinity ) return *this;
     64                unsafeCost += inc;
     65                return *this;
    5466        }
    5567
    56         inline void Cost::incPoly( int inc ) {
    57                 poly += inc;
     68        inline Cost & Cost::incPoly( int inc ) {
     69                if ( *this == infinity ) return *this;
     70                polyCost += inc;
     71                return *this;
    5872        }
    5973
    60         inline void Cost::incSafe( int inc ) {
    61                 safe += inc;
     74        inline Cost & Cost::incSafe( int inc ) {
     75                if ( *this == infinity ) return *this;
     76                safeCost += inc;
     77                return *this;
     78        }
     79
     80        inline Cost & Cost::incReference( int inc ) {
     81                if ( *this == infinity ) return *this;
     82                referenceCost += inc;
     83                return *this;
    6284        }
    6385
    6486        inline Cost Cost::operator+( const Cost &other ) const {
    65                 return Cost( unsafe + other.unsafe, poly + other.poly, safe + other.safe );
     87                if ( *this == infinity || other == infinity ) return infinity;
     88                return Cost( unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, referenceCost + other.referenceCost );
    6689        }
    6790
    6891        inline Cost Cost::operator-( const Cost &other ) const {
    69                 return Cost( unsafe - other.unsafe, poly - other.poly, safe - other.safe );
     92                if ( *this == infinity || other == infinity ) return infinity;
     93                return Cost( unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, referenceCost - other.referenceCost );
    7094        }
    7195
    7296        inline Cost &Cost::operator+=( const Cost &other ) {
    73                 unsafe += other.unsafe;
    74                 poly += other.poly;
    75                 safe += other.safe;
     97                if ( *this == infinity ) return *this;
     98                if ( other == infinity ) {
     99                        *this = infinity;
     100                        return *this;
     101                }
     102                unsafeCost += other.unsafeCost;
     103                polyCost += other.polyCost;
     104                safeCost += other.safeCost;
     105                referenceCost += other.referenceCost;
    76106                return *this;
    77107        }
    78108
    79109        inline bool Cost::operator<( const Cost &other ) const {
    80             if ( *this == infinity ) return false;
    81             if ( other == infinity ) return true;
    82             if ( unsafe > other.unsafe ) {
     110                if ( *this == infinity ) return false;
     111                if ( other == infinity ) return true;
     112
     113                if ( unsafeCost > other.unsafeCost ) {
    83114                        return false;
    84             } else if ( unsafe < other.unsafe ) {
     115                } else if ( unsafeCost < other.unsafeCost ) {
    85116                        return true;
    86             } else if ( poly > other.poly ) {
     117                } else if ( polyCost > other.polyCost ) {
    87118                        return false;
    88             } else if ( poly < other.poly ) {
     119                } else if ( polyCost < other.polyCost ) {
    89120                        return true;
    90             } else if ( safe > other.safe ) {
     121                } else if ( safeCost > other.safeCost ) {
    91122                        return false;
    92             } else if ( safe < other.safe ) {
     123                } else if ( safeCost < other.safeCost ) {
    93124                        return true;
    94             } else {
     125                } else if ( referenceCost > other.referenceCost ) {
    95126                        return false;
    96             } // if
     127                } else if ( referenceCost < other.referenceCost ) {
     128                        return true;
     129                } else {
     130                        return false;
     131                } // if
    97132        }
    98133
    99134        inline bool Cost::operator==( const Cost &other ) const {
    100                 return unsafe == other.unsafe
    101                         && poly == other.poly
    102                         && safe == other.safe;
     135                return unsafeCost == other.unsafeCost
     136                        && polyCost == other.polyCost
     137                        && safeCost == other.safeCost
     138                        && referenceCost == other.referenceCost;
    103139        }
    104140
     
    108144
    109145        inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
    110                 os << "( " << cost.unsafe << ", " << cost.poly << ", " << cost.safe << " )";
     146                os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " << cost.safeCost << ", " << cost.referenceCost << " )";
    111147                return os;
    112148        }
  • src/ResolvExpr/PtrsAssignable.cc

    r135b431 r6b224a52  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // PtrsAssignable.cc -- 
     7// PtrsAssignable.cc --
    88//
    99// Author           : Richard C. Bilson
     
    8282        void PtrsAssignable::visit(  __attribute__((unused)) UnionInstType *inst ) {}
    8383
    84         void PtrsAssignable::visit( EnumInstType *inst ) {
    85                 if ( dynamic_cast< EnumInstType* >( inst ) ) {
     84        void PtrsAssignable::visit( EnumInstType * ) {
     85                if ( dynamic_cast< EnumInstType* >( dest ) ) {
    8686                        result = 1;
    87                 } else if ( BasicType *bt = dynamic_cast< BasicType* >( inst ) ) {
     87                } else if ( BasicType *bt = dynamic_cast< BasicType* >( dest ) ) {
    8888                        result = bt->get_kind() == BasicType::SignedInt;
    8989                }
     
    104104        void PtrsAssignable::visit(  __attribute__((unused)) ZeroType *zeroType ) {}
    105105        void PtrsAssignable::visit(  __attribute__((unused)) OneType *oneType ) {}
    106        
     106
    107107} // namespace ResolvExpr
    108108
  • src/ResolvExpr/ResolveTypeof.cc

    r135b431 r6b224a52  
    6565                        assert( newExpr->has_result() && ! newExpr->get_result()->isVoid() );
    6666                        Type *newType = newExpr->get_result();
     67                        newExpr->set_result( nullptr );
    6768                        delete typeofType;
     69                        delete newExpr;
    6870                        return newType;
    6971                } // if
  • src/ResolvExpr/Unify.cc

    r135b431 r6b224a52  
    5353                virtual void visit(PointerType *pointerType);
    5454                virtual void visit(ArrayType *arrayType);
     55                virtual void visit(ReferenceType *refType);
    5556                virtual void visit(FunctionType *functionType);
    5657                virtual void visit(StructInstType *aggregateUseType);
     
    153154
    154155        bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     156                // remove references from other, so that type variables can only bind to value types
     157                other = other->stripReferences();
    155158                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
    156159                assert( tyvar != openVars.end() );
     
    387390                                } // if
    388391                        } else {
     392                                common = type1->clone();
     393                                common->get_qualifiers() = tq1 | tq2;
    389394                                result = true;
    390395                        } // if
     
    436441                        markAssertions( haveAssertions, needAssertions, pointerType );
    437442                        markAssertions( haveAssertions, needAssertions, otherPointer );
     443                } // if
     444        }
     445
     446        void Unify::visit(ReferenceType *refType) {
     447                if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
     448                        result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     449                        markAssertions( haveAssertions, needAssertions, refType );
     450                        markAssertions( haveAssertions, needAssertions, otherRef );
    438451                } // if
    439452        }
  • src/ResolvExpr/typeops.h

    r135b431 r6b224a52  
    6666        Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );
    6767
    68         template< typename SrcIterator, typename DestIterator >
    69         Cost castCostList( SrcIterator srcBegin, SrcIterator srcEnd, DestIterator destBegin, DestIterator destEnd, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    70                 Cost ret;
    71                 if ( destBegin == destEnd ) {
    72                         if ( srcBegin == srcEnd ) {
    73                                 return Cost::zero;
    74                         } else {
    75                                 return Cost( 0, 0, 1 );
    76                         } // if
    77                 } // if
    78                 while ( srcBegin != srcEnd && destBegin != destEnd ) {
    79                         Cost thisCost = castCost( *srcBegin++, *destBegin++, indexer, env );
    80                         if ( thisCost == Cost::infinity ) {
    81                                 return Cost::infinity;
    82                         } // if
    83                         ret += thisCost;
    84                 } // while
    85                 if ( srcBegin == srcEnd && destBegin == destEnd ) {
    86                         return ret;
    87                 } else {
    88                         return Cost::infinity;
    89                 } // if
    90         }
    91 
    9268        // in ConversionCost.cc
    9369        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );
    94 
    95         template< typename SrcIterator, typename DestIterator >
    96         Cost conversionCostList( SrcIterator srcBegin, SrcIterator srcEnd, DestIterator destBegin, DestIterator destEnd, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    97                 Cost ret;
    98                 while ( srcBegin != srcEnd && destBegin != destEnd ) {
    99                         Cost thisCost = conversionCost( *srcBegin++, *destBegin++, indexer, env );
    100                         if ( thisCost == Cost::infinity ) {
    101                                 return Cost::infinity;
    102                         } // if
    103                         ret += thisCost;
    104                 } // while
    105                 if ( srcBegin == srcEnd && destBegin == destEnd ) {
    106                         return ret;
    107                 } else {
    108                         return Cost::infinity;
    109                 } // if
    110         }
    11170
    11271        // in PtrsAssignable.cc
Note: See TracChangeset for help on using the changeset viewer.