fnovload.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,907 行 · 第 1/5 页

C
1,907
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "plusplus.h"

#include <assert.h>

#include "errdefns.h"
#include "fnovload.h"
#include "cgfront.h"
#include "memmgr.h"
#include "carve.h"
#include "vbuf.h"
#include "ring.h"
#include "fmtsym.h"
#include "toggle.h"
#include "template.h"
#include "initdefs.h"
#include "dbg.h"
#ifndef NDEBUG
#include "pragdefn.h"
#endif


//#define NEW_TRIVIAL_RULE

typedef enum                    // comparison and resolution results
{   OV_CMP_SAME,                // no difference
    OV_CMP_BETTER_FIRST,        // first argument is better
    OV_CMP_BETTER_SECOND,       // second argument is better
    OV_CMP_UNDEFINED            // result is undefined
} OV_RESULT;

typedef struct                  // FNOV_INFO -- overload information
{
    arg_list* alist;            // - argument definition
    PTREE* plist;               // - arguments used
    FNOV_LIST** pcandidates;    // - hdr: candidates
    FNOV_LIST** pmatch;         // - hdr: matches
    FNOV_LIST* candfunc;        // - candidate function
    FNOV_CONTROL control;       // - control item
    FNOV_RESULT result;         // - result for candidates
    FNOV_DIAG *fnov_diag;       // - information used for diagnosis
    uint_8 has_template :1;     // - TRUE ==> has template candidate
} FNOV_INFO;

#define CACHE_FNOVRANK_SIZE     16

// carve storage for fnov list structures
#define BLOCK_FNOVLIST      16
static carve_t carveFNOVLIST;
#define BLOCK_ManyFNOVRANK  16
static carve_t carveManyFNOVRANK;

// static storage for diagnostic lists
#define LIST_FREE       -1


//--------------------------------------------------------------------
// Manage # of candidates
//--------------------------------------------------------------------

static void fnovNumCandidatesSet( FNOV_DIAG *fnov_diag, FNOV_LIST *candidates )
{
    if( fnov_diag != NULL ) {
        if( fnov_diag->num_candidates == LIST_FREE ) {
            fnov_diag->num_candidates = RingCount( candidates );
        }
    }
}


//--------------------------------------------------------------------
// FNOV_RANK Support
//--------------------------------------------------------------------

static FNOV_RANK *newRank( unsigned n )
{
    FNOV_RANK *rank;

    if( n > CACHE_FNOVRANK_SIZE ) {
        rank = CMemAlloc( sizeof( *rank ) * n );
    } else {
        rank = CarveAlloc( carveManyFNOVRANK );
    }
    return( rank );
}

static void deleteRank( FNOV_RANK *rank, unsigned n )
{
    if( n > CACHE_FNOVRANK_SIZE ) {
        CMemFree( rank );
    } else {
        CarveFree( carveManyFNOVRANK, rank );
    }
}

static void initRankVector( FNOV_CONTROL control, FNOV_RANK *rv, int num_args )
/***************************************************************************/
// initialize vector of rank information
{
    int        i;
    FNOV_RANK *rank;

    if( num_args == 0 ) num_args = 1;
    rank = rv;
    memset( rank, 0, sizeof( *rank ) * num_args );
    for( i = num_args ; i > 0 ; i--, rank++ ) {
        rank->rank = OV_RANK_INVALID;
        rank->control = control;
    }
    // for member functions, don't check u-d conversion on this ptr
    if( control & FNC_MEMBER ) {
        rv->control |= FNC_EXCLUDE_UDCONV;
    }
    // for standard operators which are member functions,
    // don't check any conversion on first parm
    if( ( control & FNC_STDOPS) && ( control & FNC_MEMBER ) ) {
        rv->control |= FNC_EXCLUDE_CONV;
    }
}

static void addRankVector( FNOV_LIST *candidate, FNOV_CONTROL control )
/*********************************************************************/
// allocate and initialize vector of rank information
{
    FNOV_RANK *rank;
    unsigned num_args;

    num_args = candidate->num_args;
    if( num_args == 0 ) {
        num_args = 1;
    }
    rank = newRank( num_args );
    initRankVector( control, rank, num_args );
    candidate->rankvector = rank;
}

static boolean hasOneArg( arg_list *arg )
{
    if( arg->num_args > 0  &&
       (arg->type_list[arg->num_args-1])->id  == TYP_DOT_DOT_DOT ) {
        return (arg->num_args == 2 || arg->num_args == 1);
        // ellipsis args take up space in array, but we want to match
        // fns with one real arg plus ellipsis args as having one arg
        // also, fns with just ellipsis args can match as having one arg
    }
    return (arg->num_args == 1);
}

static void udcRankCtor( FNOV_LIST *list, TYPE src, TYPE tgt,
/**********************************************************/
FNOV_UDC_CONTROL control, FNOV_INTRNL_CONTROL ictl, PTREE *src_ptree )
// rank ctors in list, going from src to tgt.
{
    FNOV_LIST   *curr;          // current element in list
    arg_list    *arg;           // arg list to ctor
    FNOV_CONTROL fnov_control;
    TYPE        inter;          // intermediate type (src->inter->tgt)
    FNOV_CONTROL curr_control;  // control for current ctor;

    if( ictl & FNOV_INTRNL_ONCE_ONLY ) {
        fnov_control = FNC_EXCLUDE_UDCONV;
    } else {
        if( !IsCopy(control)  ||                // direct or
            ( ictl & FNOV_INTRNL_DERIVED ) ) {  // copy and derived
            fnov_control = FNC_DEFAULT; // allow second UDC
        } else {
            fnov_control = FNC_EXCLUDE_UDCONV;
        }
    }
    RingIterBeg( list, curr ) {
        arg = SymFuncArgList( curr->sym );
        curr_control = fnov_control;
        if( hasOneArg( arg ) &&
            ( ( control & FNOV_UDC_USE_EXPLICIT ) ||
              ( curr->sym->sym_type->flag & TF1_EXPLICIT ) == 0 ) ) {
            inter = arg->type_list[0];
            if( ( ictl & FNOV_INTRNL_EXCLUDE_UDCONV_PARAM ) == 0 &&
                IsCopy(control) && CompFlags.extensions_enabled &&
                ( ictl & FNOV_INTRNL_ONCE_ONLY ) == 0 ) {
                TYPE    tgt_type;
                TYPE    inter_type;
                tgt_type = ClassTypeForType( tgt );
                inter_type = ClassTypeForType(inter);
                if( tgt_type != inter_type ) {
                    // copy case, extensions enabled
                    // tgt and inter not same
                    // allow second UDC, but not another
                    curr_control = FNC_DEFAULT | FNC_RANKING_CTORS;
                }
            }
            if( ictl & FNOV_INTRNL_8_5_3_ANSI ) {
                curr_control |= FNC_8_5_3_ANSI;
            }
            if( ictl & FNOV_INTRNL_STDOP_CV_VOID ) {
                curr_control |= FNC_STDOP_CV_VOID;
            }
            addRankVector( curr, curr_control );
            FnovArgRank( src, inter, src_ptree, curr->rankvector );
        } else {
            addRankVector( curr, curr_control );
            curr->rankvector->rank = OV_RANK_NO_MATCH;
        }
    } RingIterEnd( curr )

}

static FNOV_SCALAR rankCtorReturn(
    FNOV_LIST *match,
    TYPE tgt,
    PTREE *src_ptree )
{
    TYPE ret_type;
    FNOV_RANK rank;

    ret_type = SymFuncReturnType( match->sym );
    // ctor type returned above is class &, but the type
    // of a ctor is defined to be just the class
    ret_type = ClassTypeForType( ret_type );
    initRankVector( FNC_EXCLUDE_UDCONV, &rank, 0 );
    FnovArgRank( ret_type, tgt, src_ptree, &rank );
    return( rank.u.no_ud );
}

static void udcRankUDCF( FNOV_LIST *list, TYPE src, TYPE tgt,
FNOV_INTRNL_CONTROL ictl, PTREE *src_ptree )
/**********************************************************/
// rank UDCFs in list, going from src to tgt.
{
    FNOV_LIST           *curr;          // current element in list
    type_flag           srcflags;
    type_flag           tgtflags;
    void                *unused;
    TYPE                ret_type;
    FNOV_CONTROL        control;

    TypeModExtract( TypeReferenced( src )
                  , &srcflags
                  , &unused
                  , TC1_NOT_ENUM_CHAR|TC1_NOT_MEM_MODEL );
    control = FNC_EXCLUDE_UDCONV;
    if( ictl & FNOV_INTRNL_STDOP_CV_VOID ) {
        control |= FNC_STDOP_CV_VOID;
    }
    RingIterBeg( list, curr ) {
        addRankVector( curr, control );
        ret_type = SymFuncReturnType( curr->sym );
        FnovArgRank( ret_type, tgt, src_ptree, curr->rankvector );
        if( SymIsThisFuncMember( curr->sym ) ) { // rank src->this
            tgtflags = curr->alist->qualifier;
            FnovCvFlagsRank( srcflags, tgtflags, &curr->thisrank );
        }
    } RingIterEnd( curr )
}

//--------------------------------------------------------------------
// FNOV_LIST Support
//--------------------------------------------------------------------

void FnovListFree( FNOV_LIST **plist )
/************************************/
// free memory used by list of overloaded functions
{
    FNOV_LIST *ptr;

    RingIterBeg( *plist, ptr ) {
        if( ptr->rankvector ) {
            deleteRank( ptr->rankvector, ptr->num_args );
        }
        if( ptr->free_args ) {
            CMemFree( ptr->alist );
        }
    } RingIterEnd( ptr )
    RingCarveFree( carveFNOVLIST, plist );
}

typedef enum                // LENT -- flags for addListEntry
{   LENT_DEFAULT    =0x00   // - default: add to candidates
,   LENT_MATCH      =0x01   // - add to matches
,   LENT_TPL_CHECK  =0x02   // - check for template candidate
,   LENT_FREE_ARGS  =0x04   // - mark args to be freed
} LENT;

static void addListEntry( FNOV_CONTROL control, FNOV_INFO *info, SYMBOL sym,
/**************************************************************************/
    arg_list *alist, LENT flags )
// add an entry to list of overloaded functions
{
    FNOV_LIST    *new;
    FNOV_LIST    **hdr;     // - header for list addition

    if( flags & LENT_MATCH ) {
        hdr = info->pmatch;
    } else {
        hdr = info->pcandidates;
    }
    // allocate and initialize the storage
    new = RingCarveAlloc( carveFNOVLIST, hdr );
    new->sym  = sym;
    new->alist = alist;
    if( control & FNC_RANK_RETURN ) {
        new->num_args = 1;
    } else {
        new->num_args = alist->num_args;
    }
    if( flags & LENT_FREE_ARGS ) {
        new->free_args = TRUE;
    } else {
        new->free_args = FALSE;
    }
    new->member = ((control & FNC_MEMBER) != 0 );
    new->stdops = ((control & FNC_STDOPS) != 0 );
    new->rankvector = NULL;
    initRankVector( FNC_DEFAULT, &new->thisrank, 1 );
    new->thisrank.rank = OV_RANK_EXACT;
    new->flags = TF1_NULL;
    if( flags & LENT_TPL_CHECK ) {
        if( SymIsFunctionTemplateModel( sym ) ) {
            info->has_template = TRUE;
        }
    }
}


//--------------------------------------------------------------------
// Diagnostic Support
//--------------------------------------------------------------------

void FnovFreeDiag( FNOV_DIAG *fnov_diag )
{
    if( fnov_diag != NULL ) {
        fnov_diag->num_candidates = LIST_FREE;
        FnovListFree( &fnov_diag->diag_ambig );
        fnov_diag->diag_ambig = NULL;
        FnovListFree( &fnov_diag->diag_reject );
        fnov_diag->diag_reject = NULL;
    }
}

static void setFnovDiagnosticAmbigList( FNOV_DIAG *fnov_diag, FNOV_LIST **ambig )
/************************************************************************/
{
    if( fnov_diag == NULL ) {
        FnovListFree( ambig );
    } else {
        if( fnov_diag->diag_ambig != NULL ) {
            FnovListFree( &fnov_diag->diag_ambig );
        }
        fnov_diag->diag_ambig = *ambig;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?