class.c

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

C
2,168
字号
/****************************************************************************
*
*                            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:  Handle processing of declarations within classes.
*
****************************************************************************/


#include "plusplus.h"

#include <malloc.h>
#include <limits.h>

#include "codegen.h"
#include "cgfront.h"
#include "errdefns.h"
#include "preproc.h"
#include "fnbody.h"
#include "ring.h"
#include "carve.h"
#include "vbuf.h"
#include "name.h"
#include "rewrite.h"
#include "yydriver.h"
#include "template.h"
#include "pcheader.h"
#include "decl.h"
#include "class.h"
#include "brinfo.h"
#include "pragdefn.h"

/*
    Future object model changes:
        - force vfptr to offset 0 (if possible)
                - ensure that the following matches VC++ under -zp8
                        struct S {
                            char c;
                            double d;
                            void virtual foo( int );
                        };
        - optimize more empty bases: when laying down a base class,
          overlay an empty base class on top of it
          (see notes\empty.c compiled with VC++)
        - record padding, stuff empty base classes into the padding
*/

static CLASS_DATA *classDataStack;

#define BLOCK_BASE_CLASS        16
#define BLOCK_VF_HIDE           16
static carve_t carveBASE_CLASS;
static carve_t carveVF_HIDE;

struct vf_hide {
    VF_HIDE             *next;
    SYMBOL_NAME         derived;
    SYMBOL_NAME         base;
};

// new offset can equal old offset for zero sized array at end of struct
#if TARGET_UINT_MAX < 0x010000
#define _CLASS_CHECK_SIZE( n, o ) \
        if( ((n) < (o)) || ((n) > TARGET_UINT_MAX) ) { \
            CErr1( ERR_MAX_STRUCT_EXCEEDED ); \
        }
#else
#define _CLASS_CHECK_SIZE( n, o ) \
        if( (n) < (o) ) { \
            CErr1( ERR_MAX_STRUCT_EXCEEDED ); \
        }
#endif

#define _IS_DEFAULT_INLINE      ( OptSize <= 50 )

enum {
    CC_CONST    = 0x01, /* first arg is const */
    CC_REF      = 0x02, /* first arg is a reference */
    CC_NULL     = 0x00
};

typedef enum {
    PROP_BASE   = 0x01, /* propagating from a base class */
    PROP_STATIC = 0x02, /* propagating from a static member */
    PROP_NULL   = 0x00
} prop_type;

static uint_16 classIndex;

#ifndef NDEBUG
void DumpClasses( void )
{
    CLASS_DATA *data;

    printf( "---\n" );
    for( data = classDataStack; data != NULL; data = data->next ) {
        extern void DumpFullType( TYPE );
        printf( "%p: ", data );
        DumpFullType( data->type );
        printf( "'%s' "
            "inline_data %p "
            "\n",
            data->name,
            data->inline_data,
            0 );
    }
}
#endif

void ClassInit( void )
/********************/
{
    carveBASE_CLASS = CarveCreate( sizeof( BASE_CLASS ), BLOCK_BASE_CLASS );
    carveVF_HIDE = CarveCreate( sizeof( VF_HIDE ), BLOCK_VF_HIDE );
    classIndex = 0;
}

void ClassFini( void )
/********************/
{
#ifndef NDEBUG
    CarveVerifyAllGone( carveVF_HIDE, "VF_HIDE" );
#endif
    CarveDestroy( carveVF_HIDE );
    CarveDestroy( carveBASE_CLASS );
}

target_offset_t PackAlignment( target_offset_t pack_amount, target_size_t size )
/******************************************************************************/
{
    target_offset_t pack_adjustment;

    if( pack_amount == 1 ) {
        return( 1 );
    }
    pack_adjustment = pack_amount;
    switch( size ) {
    case 1:
        pack_adjustment = 1;
        break;
    case 2:
        if( pack_adjustment > 2 ) {
            pack_adjustment = 2;
        }
        break;
    case 4:
        if( pack_adjustment > 4 ) {
            pack_adjustment = 4;
        }
        break;
    case 8:
        if( pack_adjustment > 8 ) {
            pack_adjustment = 8;
        }
        break;
    }
    return( pack_adjustment );
}

static target_offset_t packSize( CLASS_DATA *data, TYPE type )
{
    target_size_t align_size;

    align_size = CgMemorySize( AlignmentType( type ) );
    return( PackAlignment( data->pack_amount, align_size ) );
}

static void doAlignment( CLASS_DATA *data, target_offset_t adjustment )
{
    target_size_t old_offset;
    target_size_t calc_offset;

    if( adjustment != 1 ) {
        old_offset = data->offset;
        calc_offset = old_offset;
        calc_offset += adjustment - 1;
        calc_offset &= ~(((target_size_t) adjustment ) - 1 );
        _CLASS_CHECK_SIZE( calc_offset, data->offset );
        data->offset = calc_offset;
        if( calc_offset != old_offset && CompFlags.warn_about_padding ) {
            CErr2( WARN_PADDING_ADDED, ( calc_offset - old_offset ) );
        }
    }
}

static target_offset_t addField( CLASS_DATA *data, target_size_t size,
                                 target_offset_t pack_amount )
{
    target_size_t calc_offset;
    target_offset_t start;
    target_offset_t save_end;

    if( pack_amount > data->max_align ) {
        data->max_align = pack_amount;
    }
    save_end = data->offset;
    if( data->is_union ) {
        data->offset = data->start;
    }
    doAlignment( data, pack_amount );
    start = data->offset;
    calc_offset = start;
    calc_offset += size;
    _CLASS_CHECK_SIZE( calc_offset, start );
    data->offset = calc_offset;
    if( data->is_union ) {
        if( save_end > data->offset ) {
            data->offset = save_end;
        }
    }
    return( start );
}

static target_offset_t addTypeField( CLASS_DATA *data, TYPE type )
{
    return( addField( data, CgMemorySize( type ), packSize( data, type ) ) );
}

static target_offset_t addZeroSizedField( CLASS_DATA *data, TYPE type )
{
    return( addField( data, 0, packSize( data, type ) ) );
}

void ClassInitState( type_flag class_variant, CLASS_INIT extra, TYPE class_mod_list )
/***********************************************************************************/
{
    CLASS_DATA *data;
    CLASS_DATA *prev_data;
    unsigned packing;
    TYPE class_mod_type;

    packing = PackAmount;
    if( extra & CLINIT_PACKED ) {
        packing = TARGET_CHAR;
    }
    data = classDataStack;
    data->sym = NULL;
    data->type = NULL;
    data->scope = NULL;
    data->info = NULL;
    data->bases = NULL;
    data->base_vbptr = NULL;
    data->base_vfptr = NULL;
    data->name = NULL;
    data->inlines = NULL;
    data->defargs = NULL;
    data->vf_hide_list = NULL;
    data->offset = 0;
    data->vb_offset = 0;
    data->vf_offset = 0;
    data->vf_index = 0;
    data->vb_index = 0;
    data->max_align = 0;
    data->pack_amount = packing;
    data->tflag = class_variant;
    data->bitfield = FALSE;
    data->defined = FALSE;
    data->local_class = FALSE;
    data->nested_class = FALSE;
    data->allow_typedef = FALSE;
    data->own_vfptr = FALSE;
    data->nameless_OK = FALSE;
    data->generic = FALSE;
    data->specific_defn = FALSE;
    data->is_explicit = TRUE;
    data->is_union = FALSE;
    data->zero_array_defd = FALSE;
    data->member_mod_adjust = FALSE;
    data->class_idiom = FALSE;
    data->class_template = FALSE;
    data->a_public = FALSE;
    data->a_protected = FALSE;
    data->a_private = FALSE;
    data->a_const = FALSE;
    data->a_reference = FALSE;
    data->has_const_copy = FALSE;
    data->has_nonconst_copy = FALSE;
    data->has_const_opeq = FALSE;
    data->has_nonconst_opeq = FALSE;
    data->has_explicit_opeq = FALSE;
    data->in_defn = FALSE;
    class_mod_type = NULL;
    if( class_mod_list != NULL ) {
        class_mod_type = ProcessClassModifiers( class_mod_list, &(data->mod_flags), &(data->fn_flags), &(data->fn_pragma) );
        data->member_mod_adjust = TRUE;
    }
    data->class_mod_type = class_mod_type;
    if( extra & CLINIT_TEMPLATE_DECL ) {
        data->class_template = TRUE;
    }
    prev_data = data->next;
    if( prev_data != NULL ) {
        if( ( prev_data->info != NULL ) && prev_data->info->defined ) {
            data->inline_data = NULL;
        } else {
            /* our inline fns go where any previous class' inline fns
             * go, but only if the previous class isn't already fully
             * defined */
            data->inline_data = prev_data->inline_data;
        }
    } else {
        data->inline_data = NULL;
    }
    switch( ScopeId( GetCurrScope() ) ) {
    case SCOPE_BLOCK:
        data->local_class = TRUE;
        break;
    case SCOPE_CLASS:
        data->nested_class = TRUE;
        break;
    case SCOPE_TEMPLATE_INST:
        data->tflag |= TF1_INSTANTIATION;
        break;
    }
    if( class_variant & (TF1_STRUCT|TF1_UNION) ) {
        data->perm = SF_NULL;
        if( class_variant & TF1_UNION ) {
            data->is_union = TRUE;
        }
    } else {
        data->perm = SF_PRIVATE;
    }
    CErrCheckpoint( &(data->errors) );
}


void ClassAddFunctionMods( TYPE fn_declarator )
/*********************************************/
{
    CLASS_DATA *data;

    data = classDataStack;
    if( data != NULL && data->member_mod_adjust ) {
        SetFnClassMods( fn_declarator, data->fn_flags, data->fn_pragma );
    }
}

void ClassPermission( symbol_flag new_perm )
/******************************************/
{
    classDataStack->perm = new_perm;
}

static void typeError( int msg, TYPE type )
{
    CErr2p( msg, type );
}

static boolean verifyNoChangePerm( CLASS_DATA *data, symbol_flag perm, char *name )
{
    if( perm != data->perm ) {
        /* data->perm is 'protected' or 'public' */
        if( data->perm & SF_PROTECTED ) {
            if( perm & SF_PRIVATE ) {
                CErr2p( ERR_ACCESS_DECL_INCREASE, name );
            } else {
                CErr2p( ERR_ACCESS_DECL_DECREASE, name );
            }
        } else {
            CErr2p( ERR_ACCESS_DECL_INCREASE, name );
        }
        return( TRUE );
    }
    return( FALSE );
}

static boolean handleAccessDeclaration( PTREE id_tree )
{
    PTREE scope_tree;
    PTREE name_tree;
    CLASS_DATA *data;
    char *name;
    TYPE type;
    TYPE udc_return_type;
    SCOPE scope;
    SCOPE curr_scope;
    SEARCH_RESULT *result;
    SYMBOL_NAME sym_name;
    SYMBOL sym;
    SYMBOL curr_sym;
    SYMBOL check_sym;
    SYMBOL access_sym;
    symbol_flag perm;
    symbol_flag curr_perm;
    boolean error_diagnosed;
    auto TOKEN_LOCN name_locn;

    error_diagnosed = FALSE;
    data = classDataStack;
    if( data->perm & SF_PRIVATE ) {
        CErr1( ERR_ACCESS_DECL_IN_PRIVATE );
        error_diagnosed = TRUE;
    }
    if( id_tree->op != PT_BINARY || id_tree->cgop != CO_COLON_COLON ) {
        /* error occurred in the C part of C::id (ignore this declaration) */
        return( error_diagnosed );
    }
    name_locn = id_tree->locn;
    name_tree = id_tree->u.subtree[1];
    name = name_tree->u.id.name;
    udc_return_type = NULL;
    if( name == CppConversionName() ) {
        udc_return_type = name_tree->type;
    }
    type = NULL;
    scope_tree = id_tree->u.subtree[0];
    if( scope_tree != NULL ) {
        type = scope_tree->type;
    }
    PTreeFreeSubtrees( id_tree );
    if( type == NULL ) {
        /* error occurred in the C part of C::id (ignore this declaration) */

⌨️ 快捷键说明

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