Changeset cce9429


Ignore:
Timestamp:
Dec 13, 2016, 6:42:39 PM (5 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, with_gc
Children:
1aa4b71
Parents:
31f379c
Message:

fix function return type in Validate and add single return decl, construct the return decl, fix polymorphic functions to use the return decl

Location:
src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Box.cc

    r31f379c rcce9429  
    131131                        ScopedMap< std::string, DeclarationWithType* > adapters;     ///< Set of adapter functions in the current scope
    132132
     133                        std::map< ApplicationExpr *, Expression * > retVals;
     134
    133135                        DeclarationWithType *retval;
    134                         bool useRetval;
    135136                        UniqueName tempNamer;
    136137                };
     
    497498                }
    498499
    499                 Pass1::Pass1() : useRetval( false ), tempNamer( "_temp" ) {}
     500                Pass1::Pass1() : tempNamer( "_temp" ) {}
    500501
    501502                /// Returns T if the given declaration is a function with parameter (T*) for some TypeInstType T, NULL otherwise
     
    667668
    668669                                DeclarationWithType *oldRetval = retval;
    669                                 bool oldUseRetval = useRetval;
    670670
    671671                                // process polymorphic return value
    672                                 retval = 0;
    673                                 if ( isDynRet( functionDecl->get_functionType() ) && functionDecl->get_linkage() == LinkageSpec::Cforall ) {
     672                                retval = nullptr;
     673                                if ( isDynRet( functionDecl->get_functionType() ) && functionDecl->get_linkage() != LinkageSpec::C ) {
    674674                                        retval = functionDecl->get_functionType()->get_returnVals().front();
    675675
     
    700700                                        if ( adapters.find( mangleName ) == adapters.end() ) {
    701701                                                std::string adapterName = makeAdapterName( mangleName );
    702                                                 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), 0 ) ) );
     702                                                adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), nullptr ) ) );
    703703                                        } // if
    704704                                } // for
     
    712712                                dtorOps.endScope();
    713713                                retval = oldRetval;
    714                                 useRetval = oldUseRetval;
    715714                                doEndScope();
    716715                        } // if
     
    724723
    725724                Expression *Pass1::mutate( CommaExpr *commaExpr ) {
    726                         bool oldUseRetval = useRetval;
    727                         useRetval = false;
     725                        // Attempting to find application expressions that were mutated by the copy constructor passes
     726                        // to use an explicit return variable, so that the variable can be reused as a parameter to the
     727                        // call rather than creating a new temp variable. Previously this step was an optimization, but
     728                        // with the introduction of tuples and UniqueExprs, it is necessary to ensure that they use the same variable.
     729                        // Essentially, looking for pattern: (x=f(...), x)
     730                        // To compound the issue, the right side can be *x, etc. because of lvalue-returning functions
     731                        if ( UntypedExpr * assign = dynamic_cast< UntypedExpr * >( commaExpr->get_arg1() ) ) {
     732                                if ( InitTweak::isAssignment( InitTweak::getFunctionName( assign ) ) ) {
     733                                        assert( assign->get_args().size() == 2 );
     734                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( assign->get_args().back() ) ) {
     735                                                // first argument is assignable, so it must be an lvalue, so it should be legal to take its address.
     736                                                retVals[appExpr] = assign->get_args().front();
     737                                        }
     738                                }
     739                        }
     740
    728741                        commaExpr->set_arg1( maybeMutate( commaExpr->get_arg1(), *this ) );
    729                         useRetval = oldUseRetval;
    730742                        commaExpr->set_arg2( maybeMutate( commaExpr->get_arg2(), *this ) );
    731743                        return commaExpr;
     
    733745
    734746                Expression *Pass1::mutate( ConditionalExpr *condExpr ) {
    735                         bool oldUseRetval = useRetval;
    736                         useRetval = false;
    737747                        condExpr->set_arg1( maybeMutate( condExpr->get_arg1(), *this ) );
    738                         useRetval = oldUseRetval;
    739748                        condExpr->set_arg2( maybeMutate( condExpr->get_arg2(), *this ) );
    740749                        condExpr->set_arg3( maybeMutate( condExpr->get_arg3(), *this ) );
     
    783792                                        } else {
    784793                                                // xxx - should this be an assertion?
    785                                                 throw SemanticError( "unbound type variable: " + tyParm->first + " in application ", appExpr );
     794                                                std::string x = env ? toString( *env ) : "missing env";
     795                                                throw SemanticError( x + "\n" + "unbound type variable: " + tyParm->first + " in application ", appExpr );
    786796                                        } // if
    787797                                } // if
     
    819829                Expression *Pass1::addRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *retType, std::list< Expression *>::iterator &arg ) {
    820830                        // Create temporary to hold return value of polymorphic function and produce that temporary as a result
    821                         // using a comma expression.  Possibly change comma expression into statement expression "{}" for multiple
    822                         // return values.
     831                        // using a comma expression.
    823832                        assert( retType );
    824                         ObjectDecl *newObj = makeTemporary( retType->clone() );
    825                         Expression *paramExpr = new VariableExpr( newObj );
     833
     834                        Expression * paramExpr = nullptr;
     835                        // try to use existing return value parameter if it exists, otherwise create a new temporary
     836                        if ( retVals.count( appExpr ) ) {
     837                                paramExpr = retVals[appExpr]->clone();
     838                        } else {
     839                                ObjectDecl *newObj = makeTemporary( retType->clone() );
     840                                paramExpr = new VariableExpr( newObj );
     841                        }
     842                        Expression * retExpr = paramExpr->clone();
    826843
    827844                        // If the type of the temporary is not polymorphic, box temporary by taking its address;
    828845                        // otherwise the temporary is already boxed and can be used directly.
    829                         if ( ! isPolyType( newObj->get_type(), scopeTyVars, env ) ) {
     846                        if ( ! isPolyType( paramExpr->get_result(), scopeTyVars, env ) ) {
    830847                                paramExpr = new AddressExpr( paramExpr );
    831848                        } // if
     
    833850                        arg++;
    834851                        // Build a comma expression to call the function and emulate a normal return.
    835                         CommaExpr *commaExpr = new CommaExpr( appExpr, new VariableExpr( newObj ) );
     852                        CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr );
    836853                        commaExpr->set_env( appExpr->get_env() );
    837854                        appExpr->set_env( 0 );
     
    851868                                Type *concrete = env->lookup( typeInst->get_name() );
    852869                                if ( concrete == 0 ) {
    853                                         throw SemanticError( "Unbound type variable " + typeInst->get_name() + " in ", appExpr );
     870                                        // xxx - should this be an assertion?
     871                                        std::string x = env ? toString( *env ) : "missing env";
     872                                        throw SemanticError( x + "\n" + "Unbound type variable " + typeInst->get_name() + " in ", appExpr );
    854873                                } // if
    855874                                return concrete;
     
    12591278                        // }
    12601279                        // std::cerr << "\n";
    1261                         bool oldUseRetval = useRetval;
    1262                         useRetval = false;
    12631280                        appExpr->get_function()->acceptMutator( *this );
    12641281                        mutateAll( appExpr->get_args(), *this );
    1265                         useRetval = oldUseRetval;
    12661282
    12671283                        assert( appExpr->get_function()->has_result() );
     
    15451561                }
    15461562
     1563                /// determines if `pref` is a prefix of `str`
     1564                bool isPrefix( const std::string & str, const std::string & pref ) {
     1565                        if ( pref.size() > str.size() ) return false;
     1566                        auto its = std::mismatch( pref.begin(), pref.end(), str.begin() );
     1567                        return its.first == pref.end();
     1568                }
     1569
    15471570                DeclarationWithType * Pass2::mutate( FunctionDecl *functionDecl ) {
    1548                         return handleDecl( functionDecl, functionDecl->get_functionType() );
     1571                        if ( ! LinkageSpec::isBuiltin( functionDecl->get_linkage() ) ) {
     1572                                // std::cerr << "mutating function: " << functionDecl->get_name() << std::endl;
     1573                        }
     1574                        functionDecl = safe_dynamic_cast< FunctionDecl * > ( handleDecl( functionDecl, functionDecl->get_functionType() ) );
     1575                        FunctionType * ftype = functionDecl->get_functionType();
     1576                        if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) {
     1577                                if ( functionDecl->get_name() != "?=?" && ! isPrefix( functionDecl->get_name(), "_thunk" ) ) { // xxx - remove check for ?=? once reference types are in; remove check for prefix once thunks properly use ctor/dtors
     1578                                        assert( ftype->get_returnVals().size() == 1 );
     1579                                        DeclarationWithType * retval = ftype->get_returnVals().front();
     1580                                        if ( retval->get_name() == "" ) {
     1581                                                retval->set_name( "_retval" );
     1582                                        }
     1583                                        functionDecl->get_statements()->get_kids().push_front( new DeclStmt( noLabels, retval ) );
     1584                                        DeclarationWithType * newRet = retval->clone(); // for ownership purposes
     1585                                        ftype->get_returnVals().front() = newRet;
     1586                                }
     1587                        }
     1588                        return functionDecl;
    15491589                }
    15501590
  • src/InitTweak/GenInit.cc

    r31f379c rcce9429  
    4646                ReturnFixer();
    4747
    48                 using GenPoly::PolyMutator::mutate;
     48                typedef GenPoly::PolyMutator Parent;
     49                using Parent::mutate;
    4950                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override;
    5051                virtual Statement * mutate( ReturnStmt * returnStmt ) override;
     
    142143                // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address
    143144                // is being returned
     145                // Note: under the assumption that assignments return *this, checking for ?=? here is an optimization, since it shouldn't be necessary to copy construct `this`. This is a temporary optimization until reference types are added, at which point this should be removed, along with the analogous optimization in copy constructor generation.
    144146                if ( returnStmt->get_expr() && returnVals.size() == 1 && funcName != "?=?" && ! returnVals.front()->get_type()->get_isLvalue() ) {
    145                         // ensure return value is not destructed by explicitly creating
    146                         // an empty SingleInit node wherein maybeConstruct is false
    147                         ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, returnVals.front()->get_type()->clone(), new ListInit( std::list<Initializer*>(), noDesignators, false ) );
    148                         stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
    149 
    150                         // and explicitly create the constructor expression separately
     147                        // explicitly construct the return value using the return expression and the retVal object
     148                        assertf( returnVals.front()->get_name() != "", "Function %s has unnamed return value\n", funcName.c_str() );
    151149                        UntypedExpr *construct = new UntypedExpr( new NameExpr( "?{}" ) );
    152                         construct->get_args().push_back( new AddressExpr( new VariableExpr( newObj ) ) );
     150                        construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) );
    153151                        construct->get_args().push_back( returnStmt->get_expr() );
    154152                        stmtsToAdd.push_back(new ExprStmt(noLabels, construct));
    155153
    156                         returnStmt->set_expr( new VariableExpr( newObj ) );
     154                        // return the retVal object
     155                        returnStmt->set_expr( new VariableExpr( returnVals.front() ) );
    157156                } // if
    158157                return returnStmt;
     
    160159
    161160        DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
    162                 // xxx - need to handle named return values - this pass may need to happen
    163                 // after resolution? the ordering is tricky because return statements must be
    164                 // constructed - the simplest way to do that (while also handling multiple
    165                 // returns) is to structure the returnVals into a tuple, as done here.
    166                 // however, if the tuple return value is structured before resolution,
    167                 // it's difficult to resolve named return values, since the name is lost
    168                 // in conversion to a tuple. this might be easiest to deal with
    169                 // after reference types are added, as it may then be possible to
    170                 // uniformly move named return values to the parameter list directly
    171161                ValueGuard< FunctionType * > oldFtype( ftype );
    172162                ValueGuard< std::string > oldFuncName( funcName );
    173163
    174164                ftype = functionDecl->get_functionType();
    175                 std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();
    176                 if ( retVals.size() > 1 ) {
    177                         TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );
    178                         ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );
    179                         retVals.clear();
    180                         retVals.push_back( newRet );
    181                 }
    182165                funcName = functionDecl->get_name();
    183                 DeclarationWithType * decl = Mutator::mutate( functionDecl );
    184                 return decl;
     166                return Parent::mutate( functionDecl );
    185167        }
    186168
  • src/SymTab/Validate.cc

    r31f379c rcce9429  
    8686        };
    8787
     88        /// Fix return types so that every function returns exactly one value
     89        class ReturnTypeFixer : public Visitor {
     90          public:
     91                static void fix( std::list< Declaration * > &translationUnit );
     92
     93                virtual void visit( FunctionType * ftype );
     94        };
     95
    8896        /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers.
    8997        class EnumAndPointerDecayPass : public Visitor {
     
    94102
    95103        /// Associates forward declarations of aggregates with their definitions
    96         class Pass2 final : public Indexer {
     104        class LinkReferenceToTypes final : public Indexer {
    97105                typedef Indexer Parent;
    98106          public:
    99                 Pass2( bool doDebug, const Indexer *indexer );
     107                LinkReferenceToTypes( bool doDebug, const Indexer *indexer );
    100108          private:
    101109                using Indexer::visit;
     
    193201        void validate( std::list< Declaration * > &translationUnit, bool doDebug ) {
    194202                EnumAndPointerDecayPass epc;
    195                 Pass2 pass2( doDebug, 0 );
     203                LinkReferenceToTypes lrt( doDebug, 0 );
    196204                Pass3 pass3( 0 );
    197205                CompoundLiteral compoundliteral;
     
    199207                EliminateTypedef::eliminateTypedef( translationUnit );
    200208                HoistStruct::hoistStruct( translationUnit );
     209                ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
    201210                autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecayPass
    202211                acceptAll( translationUnit, epc );
    203                 acceptAll( translationUnit, pass2 );
     212                acceptAll( translationUnit, lrt );
    204213                ReturnChecker::checkFunctionReturns( translationUnit );
    205214                compoundliteral.mutateDeclarationList( translationUnit );
     
    210219        void validateType( Type *type, const Indexer *indexer ) {
    211220                EnumAndPointerDecayPass epc;
    212                 Pass2 pass2( false, indexer );
     221                LinkReferenceToTypes lrt( false, indexer );
    213222                Pass3 pass3( indexer );
    214223                type->accept( epc );
    215                 type->accept( pass2 );
     224                type->accept( lrt );
    216225                type->accept( pass3 );
    217226        }
     
    324333        }
    325334
    326         Pass2::Pass2( bool doDebug, const Indexer *other_indexer ) : Indexer( doDebug ) {
     335        LinkReferenceToTypes::LinkReferenceToTypes( bool doDebug, const Indexer *other_indexer ) : Indexer( doDebug ) {
    327336                if ( other_indexer ) {
    328337                        indexer = other_indexer;
     
    332341        }
    333342
    334         void Pass2::visit( StructInstType *structInst ) {
     343        void LinkReferenceToTypes::visit( StructInstType *structInst ) {
    335344                Parent::visit( structInst );
    336345                StructDecl *st = indexer->lookupStruct( structInst->get_name() );
     
    346355        }
    347356
    348         void Pass2::visit( UnionInstType *unionInst ) {
     357        void LinkReferenceToTypes::visit( UnionInstType *unionInst ) {
    349358                Parent::visit( unionInst );
    350359                UnionDecl *un = indexer->lookupUnion( unionInst->get_name() );
     
    359368        }
    360369
    361         void Pass2::visit( TraitInstType *contextInst ) {
     370        void LinkReferenceToTypes::visit( TraitInstType *contextInst ) {
    362371                Parent::visit( contextInst );
    363372                if ( contextInst->get_name() == "sized" ) {
     
    398407        }
    399408
    400         void Pass2::visit( StructDecl *structDecl ) {
     409        void LinkReferenceToTypes::visit( StructDecl *structDecl ) {
    401410                // visit struct members first so that the types of self-referencing members are updated properly
    402411                Parent::visit( structDecl );
     
    412421        }
    413422
    414         void Pass2::visit( UnionDecl *unionDecl ) {
     423        void LinkReferenceToTypes::visit( UnionDecl *unionDecl ) {
    415424                Parent::visit( unionDecl );
    416425                if ( ! unionDecl->get_members().empty() ) {
     
    425434        }
    426435
    427         void Pass2::visit( TypeInstType *typeInst ) {
     436        void LinkReferenceToTypes::visit( TypeInstType *typeInst ) {
    428437                if ( NamedTypeDecl *namedTypeDecl = lookupType( typeInst->get_name() ) ) {
    429438                        if ( TypeDecl *typeDecl = dynamic_cast< TypeDecl * >( namedTypeDecl ) ) {
     
    747756                return new VariableExpr( newtempvar );
    748757        }
     758
     759        void ReturnTypeFixer::fix( std::list< Declaration * > &translationUnit ) {
     760                ReturnTypeFixer fixer;
     761                acceptAll( translationUnit, fixer );
     762        }
     763
     764        void ReturnTypeFixer::visit( FunctionType * ftype ) {
     765                static UniqueName tempNamer( "_retval" );
     766
     767                // xxx - need to handle named return values - this information needs to be saved somehow
     768                // so that resolution has access to the names.
     769                // Note that this pass needs to happen early so that other passes which look for tuple types
     770                // find them in all of the right places, including function return types.
     771                std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();
     772                if ( retVals.size() > 1 ) {
     773                        // generate a single return parameter which is the tuple of all of the return values
     774                        TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );
     775                        // ensure return value is not destructed by explicitly creating an empty ListInit node wherein maybeConstruct is false.
     776                        ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );
     777                        deleteAll( retVals );
     778                        retVals.clear();
     779                        retVals.push_back( newRet );
     780                } else if ( retVals.size() == 1 ) {
     781                        // ensure other return values have a name
     782                        DeclarationWithType * ret = retVals.front();
     783                        if ( ret->get_name() == "" ) {
     784                                ret->set_name( tempNamer.newName() );
     785                        }
     786                }
     787        }
    749788} // namespace SymTab
    750789
Note: See TracChangeset for help on using the changeset viewer.