template.c

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

C
2,056
字号
/****************************************************************************
*
*                            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 "cgfront.h"
#include "errdefns.h"
#include "rewrite.h"
#include "preproc.h"
#include "ring.h"
#include "stack.h"
#include "memmgr.h"
#include "class.h"
#include "name.h"
#include "yydriver.h"
#include "fnovload.h"
#include "context.h"
#include "template.h"
#include "pcheader.h"
#include "initdefs.h"
#ifndef NDEBUG
#include "pragdefn.h"
#include "dbg.h"
#endif

#define BLOCK_TEMPLATE_INFO     16
#define BLOCK_TEMPLATE_SPECIALIZATION 16
#define BLOCK_CLASS_INST        32
#define BLOCK_TEMPLATE_MEMBER   32
#define BLOCK_FN_TEMPLATE_DEFN  16
static carve_t carveTEMPLATE_INFO;
static carve_t carveTEMPLATE_SPECIALIZATION;
static carve_t carveCLASS_INST;
static carve_t carveTEMPLATE_MEMBER;
static carve_t carveFN_TEMPLATE_DEFN;

static TEMPLATE_DATA *currentTemplate;
static TEMPLATE_INFO *allClassTemplates;
static FN_TEMPLATE_DEFN *allFunctionTemplates;  // only ones with definitions
static struct {
    unsigned            max_depth;
    unsigned            curr_depth;
    tc_fn_control       fn_control;
    SYMBOL              translate_fn;
    TYPE                extra_member_class;
    unsigned            keep_going : 1;
    unsigned            extra_members : 1;
    unsigned            depth_diagnosed : 1;
} templateData;

static CNV_DIAG diagTempParm =  // DIAGNOSIS FOR TEMPLATE ARGUMENT CONVERSION
    { ERR_PARM_IMPOSSIBLE
    , ERR_PARM_AMBIGUOUS
    , ERR_CALL_WATCOM
    , ERR_PARM_PRIVATE
    , ERR_PARM_PROTECTED
    };

enum template_context_type {
    TCTX_CLASS_DEFN     = 1,    // instantiating template class defn
    TCTX_FN_DEFN        = 2,    // instantiating template function defn
    TCTX_MEMBER_DEFN    = 3,    // instantiating template class member defn
    TCTX_FN_BIND        = 4,    // binding a function template to arguments
    TCTX_FN_BIND_AND_GEN= 5,    // binding a function template to a fn sym
    TCTX_NULL           = 0
};

typedef struct template_context TEMPLATE_CONTEXT;
struct template_context {
    TEMPLATE_CONTEXT            *prev;
    TOKEN_LOCN                  *locn;
    union {
        SYMBOL                  sym;    // FN_DEFN, FN_BIND
        SCOPE                   scope;  // CLASS_DEFN
        void                    *any;
    } u;
    enum template_context_type  id;
};

static struct {
    NESTED_POST_CONTEXT         registration;
    TEMPLATE_CONTEXT            *inst_stack;
} activeInstantiations;

static SUICIDE_CALLBACK templateSuicide;

static void injectTemplateParm( SCOPE scope, PTREE parm, char *name );


static void templateSuicideHandler( void )
{
    activeInstantiations.inst_stack = NULL;
    templateData.curr_depth = 0;
}

static SYMBOL firstSymbol( SCOPE scope )
{
    SYMBOL first;

    first = ScopeOrderedFirst( scope );
    DbgAssert( first != NULL );
    return( first );
}

static void verifyOKToProceed( TOKEN_LOCN *locn )
{
    templateData.curr_depth++;
    if( templateData.curr_depth > templateData.max_depth ) {
        if( ! templateData.depth_diagnosed ) {
            templateData.depth_diagnosed = TRUE;
            SetErrLoc( locn );
            CErr2( ERR_TEMPLATE_DEPTH_EXHAUSTED, templateData.max_depth * 2 );
            CSuicide();
        }
    }
}

static void pushInstContext( TEMPLATE_CONTEXT *ctx,
                             enum template_context_type id,
                             TOKEN_LOCN *locn, void *extra_info )
{
    verifyOKToProceed( locn );
    ctx->id = id;
    ctx->locn = locn;
    ctx->u.any = extra_info;
    StackPush( &(activeInstantiations.inst_stack), ctx );
}

static void popInstContext( void )
{
    templateData.curr_depth--;
    StackPop( &(activeInstantiations.inst_stack) );
}

static TYPE extractTemplateClass( TEMPLATE_CONTEXT *ctx )
{
    SYMBOL sym;

    sym = firstSymbol( ctx->u.scope );
    if( sym == NULL ) {
        return( TypeError );
    }
    DbgAssert( sym->id == SC_TYPEDEF );
    return( sym->sym_type );
}

static void displayActiveInstantiations( NESTED_POST_CONTEXT *blk )
{
    TEMPLATE_CONTEXT *ctx;

#ifndef NDEBUG
    if( blk != &(activeInstantiations.registration) ) {
        CFatal( "registered call-back for template locations incorrect" );
    }
#else
    blk = blk;
#endif
    Stack_forall( activeInstantiations.inst_stack, ctx ) {
        if( ctx->locn != NULL ) {
            switch( ctx->id ) {
            case TCTX_CLASS_DEFN:
                AddNoteMessage( INF_TEMPLATE_CLASS_DEFN_TRACEBACK,
                                extractTemplateClass( ctx ), ctx->locn );
                break;
            case TCTX_FN_DEFN:
                AddNoteMessage( INF_TEMPLATE_FN_DEFN_TRACEBACK,
                                ctx->u.sym, ctx->locn );
                break;
            case TCTX_MEMBER_DEFN:
                AddNoteMessage( INF_TEMPLATE_MEMBER_DEFN_TRACEBACK,
                                ctx->locn );
                break;
            case TCTX_FN_BIND:
                AddNoteMessage( INF_TEMPLATE_FN_BIND_TRACEBACK,
                                ctx->u.sym, ctx->locn );
                break;
            case TCTX_FN_BIND_AND_GEN:
                AddNoteMessage( INF_TEMPLATE_FN_BIND_AND_GEN_TRACEBACK,
                                ctx->u.sym, ctx->locn );
                break;
            }
        }
    }
}

void TemplateSetDepth( unsigned depth )
/*************************************/
{
    if( depth < 2 ) {
        /* we need at least 2 in order to bind a function */
        depth = 2;
    }
    templateData.max_depth = depth;
}

static void templateInit( INITFINI* defn )
{
    defn = defn;
    if( CompFlags.dll_subsequent ) {
        currentTemplate = NULL;
        allClassTemplates = NULL;
        allFunctionTemplates = NULL;
        memset( &templateData, 0, sizeof( templateData ) );
    }
    templateData.max_depth = TEMPLATE_MAX_DEPTH;
    activeInstantiations.registration.call_back = displayActiveInstantiations;
    CtxRegisterPostContext( &(activeInstantiations.registration) );
    templateSuicide.call_back = templateSuicideHandler;
    RegisterSuicideCallback( &templateSuicide );
    carveTEMPLATE_INFO = CarveCreate( sizeof( TEMPLATE_INFO ), BLOCK_TEMPLATE_INFO );
    carveTEMPLATE_SPECIALIZATION = CarveCreate( sizeof( TEMPLATE_SPECIALIZATION ), BLOCK_TEMPLATE_SPECIALIZATION );
    carveCLASS_INST = CarveCreate( sizeof( CLASS_INST ), BLOCK_CLASS_INST );
    carveTEMPLATE_MEMBER = CarveCreate( sizeof( TEMPLATE_MEMBER ), BLOCK_TEMPLATE_MEMBER );
    carveFN_TEMPLATE_DEFN = CarveCreate( sizeof( FN_TEMPLATE_DEFN ), BLOCK_FN_TEMPLATE_DEFN );
}

static void templateFini( INITFINI *defn )
{
    defn = defn;
    CarveDestroy( carveTEMPLATE_INFO );
    CarveDestroy( carveTEMPLATE_SPECIALIZATION );
    CarveDestroy( carveCLASS_INST );
    CarveDestroy( carveTEMPLATE_MEMBER );
    CarveDestroy( carveFN_TEMPLATE_DEFN );
}

INITDEFN( template, templateInit, templateFini )

static TYPE setArgIndex( SYMBOL sym, unsigned index )
{
    TYPE type;

    type = sym->sym_type;
    DbgAssert( type->id == TYP_GENERIC );
    DbgAssert( type->next == NULL );
    type->u.g.index = index;
    type = CheckDupType( type );
    sym->sym_type = type;
    return type;
}

void TemplateDeclInit( TEMPLATE_DATA *data )
/***********************************************************/
{
    StackPush( &currentTemplate, data );
    CErrCheckpoint( &(data->errors) );
    data->all_generic = TRUE;
    data->args = NULL;
    data->nr_args = 0;
    data->spec_args = NULL;
    data->unbound_type = NULL;
    data->decl_scope = ScopeBegin( SCOPE_TEMPLATE_DECL );
    data->defn = NULL;
    data->member_defn = NULL;
    data->template_name = NULL;
    data->template_scope = NULL;
    data->locn.src_file = NULL;
    data->defn_found = FALSE;
    data->member_found = FALSE;
    data->defn_added = FALSE;
}

static void validateNonTypeParameterType( TYPE type )
{
    TYPE trimmed_type;

    trimmed_type = TypedefModifierRemoveOnly( type );
    if( ( trimmed_type->id == TYP_POINTER ) // reference is also ok
     || ( trimmed_type->id == TYP_GENERIC ) ) {
        return;
    }

    if( IntegralType( trimmed_type ) == NULL ) {
        CErr2p( ERR_INVALID_TEMPLATE_ARG_TYPE, trimmed_type );
    }
}

void TemplateDeclAddArgument( DECL_INFO *new_dinfo )
{
    SYMBOL sym;
    char *name;

    currentTemplate->args = AddArgument( currentTemplate->args, new_dinfo );
    currentTemplate->nr_args++;

    name = new_dinfo->name;
    sym = new_dinfo->generic_sym;

    if( sym != NULL ) {
        /* template type parameter */
        new_dinfo->type = setArgIndex( sym, currentTemplate->nr_args );
        DbgAssert( name != NULL );
        sym = ScopeInsert( GetCurrScope(), sym, name );
    } else if( ( new_dinfo->type != NULL ) ) {
        /* template non-type parameter */
        currentTemplate->all_generic = FALSE;
        if( name != NULL ) {
            sym = ScopeInsert( GetCurrScope(),
                               AllocTypedSymbol( new_dinfo->type ), name );
        }
        validateNonTypeParameterType( new_dinfo->type );
    }
}

static unsigned getArgList( DECL_INFO *args, TYPE *type_list, char **names, REWRITE **defarg_list )
{
    DECL_INFO *curr;
    unsigned count;

    count = 0;
    RingIterBeg( args, curr ) {
        if( type_list != NULL ) {
            type_list[count] = curr->type;
        }
        if( names != NULL ) {
            names[count] = curr->name;
        }
        if( defarg_list != NULL ) {
            /*
            //  Ensure that we NULL out curr->defarg_rewrite or else
            //  when we delete the DECL_INFO, the rewrite element gets
            //  freed as well. The rewrite info will be freed when the
            //  the template info is freed.
            */
            defarg_list[count] = curr->defarg_rewrite;
            curr->defarg_rewrite = NULL;
        }
        ++count;
    } RingIterEnd( curr )
    return( count );
}

static TEMPLATE_SPECIALIZATION *newTemplateSpecialization(
    TEMPLATE_DATA *data, TEMPLATE_INFO *tinfo )
{
    DECL_INFO *args;
    TEMPLATE_SPECIALIZATION *tspec;
    TEMPLATE_SPECIALIZATION *tprimary;
    unsigned arg_count;

    tinfo->nr_specs++;

    args = data->args;
    arg_count = getArgList( args, NULL, NULL, NULL );
    tspec = RingCarveAlloc( carveTEMPLATE_SPECIALIZATION,
                            &tinfo->specializations );
    tprimary = RingFirst( tinfo->specializations );

    tspec->tinfo = tinfo;
    tspec->instantiations = NULL;
    tspec->member_defns = NULL;
    tspec->decl_scope = ( arg_count > 0 ) ? data->decl_scope : NULL;
    TokenLocnAssign( tspec->locn, data->locn );
    tspec->num_args = arg_count;
    tspec->type_list = CPermAlloc( arg_count * sizeof( TYPE ) );
    tspec->arg_names = CPermAlloc( arg_count * sizeof( char * ) );
    tspec->spec_args = data->spec_args;
    data->spec_args = NULL;
    tspec->ordering = NULL;
    tspec->defn = NULL;
    tspec->corrupted = FALSE;
    tspec->defn_found = FALSE;
    tspec->free = FALSE;

    getArgList( args, tspec->type_list, tspec->arg_names, NULL );
    return( tspec );
}

static TEMPLATE_INFO *newTemplateInfo( TEMPLATE_DATA *data )
{
    DECL_INFO *args;
    TEMPLATE_INFO *tinfo;
    TEMPLATE_SPECIALIZATION *tprimary;
    unsigned arg_count;

    args = data->args;
    arg_count = getArgList( args, NULL, NULL, NULL );
    if( arg_count == 0 ) {
        CErr1( ERR_TEMPLATE_MUST_HAVE_ARGS );
    }

    tinfo = RingCarveAlloc( carveTEMPLATE_INFO, &allClassTemplates );
    tinfo->specializations = NULL;
    tinfo->nr_specs = 0;

⌨️ 快捷键说明

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