static cmp_type CompatibleType( TYPEPTR typ1, TYPEPTR typ2, bool assignment, bool null_ptr ) { cmp_type ret_val; cmp_type ret_pq; type_modifiers typ1_flags, typ2_flags; int ptr_indir_level; ptr_indir_level = 0; typ1_flags = FLAG_NONE; typ2_flags = FLAG_NONE; ret_pq = OK; typ1 = SkipTypeFluff( typ1 ); // skip typedefs go into enums base typ2 = SkipTypeFluff( typ2 ); if( typ1->decl_type == TYPE_POINTER && typ2->decl_type == TYPE_POINTER ) { // top level pointer typ1_flags = typ1->u.p.decl_flags; typ2_flags = typ2->u.p.decl_flags; // Special dispensation: assigning null pointer constant is allowed even // when the pointer size doesn't match. Required for MS compatibility. if( assignment && !null_ptr ) { type_modifiers subnot; subnot = SUBNOT( typ1_flags, typ2_flags, MASK_QUALIFIERS ); if( subnot ) { // allow void * = unaligned * if( subnot & (MASK_QUALIFIERS & ~FLAG_UNALIGNED) ) { ret_pq = PQ; } else if( subnot & FLAG_UNALIGNED) { align_type align1; align1 = GetTypeAlignment( typ1->object ); if( align1 > 1 ) { ret_pq = PQ; } } } if( (typ1_flags & MASK_ALL_MEM_MODELS) != (typ2_flags & MASK_ALL_MEM_MODELS) ) { target_size size1, size2; size1 = TypeSize( typ1 ); size2 = TypeSize( typ2 ); if( size1 < size2 ) { ret_pq = PT; } else if( size1 > size2 ) { ret_pq = PX; } } } typ1 = typ1->object; typ2 = typ2->object; ++ptr_indir_level; } ret_val = DoCompatibleType( typ1, typ2, ptr_indir_level ); if( ret_val == OK ) { ret_val = ret_pq; } return( ret_val ); }
static cmp_type DoCompatibleType( TYPEPTR typ1, TYPEPTR typ2, int ptr_indir_level ) { cmp_type ret_val; type_modifiers typ1_flags, typ2_flags; typ1_flags = FLAG_NONE; typ2_flags = FLAG_NONE; ret_val = OK; for( ;; ) { // * [] loop typ1 = SkipTypeFluff( typ1 ); // skip typedefs, go into enum base typ2 = SkipTypeFluff( typ2 ); if( typ1 == typ2 ) break; if( typ1->decl_type != typ2->decl_type ) break; if( typ1->decl_type == TYPE_ARRAY ) { /* See C99, 6.7.5.2p5 */ if( typ1->u.array->dimension && typ2->u.array->dimension ) { if( typ1->u.array->dimension != typ2->u.array->dimension ) { ret_val = PM; } } } else if( typ1->decl_type == TYPE_POINTER ) { typ1_flags = typ1->u.p.decl_flags; typ2_flags = typ2->u.p.decl_flags; if( (typ1_flags & MASK_QUALIFIERS) != (typ2_flags & MASK_QUALIFIERS) ) { if( ret_val == OK ) { //PM is a worse case ret_val = PQ; } } if( (typ1_flags & MASK_ALL_MEM_MODELS) != (typ2_flags & MASK_ALL_MEM_MODELS) ) { if( ( (typ1_flags & MASK_ALL_MEM_MODELS) != FLAG_NONE // if same as mem model ok && (typ2_flags & MASK_ALL_MEM_MODELS) != FLAG_NONE ) || TypeSize( typ1 ) != TypeSize( typ2 ) ) { return( NO ); } } ++ptr_indir_level; } else { break; } typ1 = typ1->object; typ2 = typ2->object; } if( typ1 != typ2 ) { // if not equal see if diff by pointers if( ptr_indir_level > 0 ) { if( typ1->decl_type == TYPE_VOID || typ2->decl_type == TYPE_VOID ) { // allow void ** with any ** (but warn about it) if( ( ptr_indir_level == 1 ) || !CompFlags.strict_ANSI ) { if( ptr_indir_level > 1 ) { ret_val = PM; } return( ret_val ); // void * and anything * } } if( typ1->decl_type == TYPE_POINTER && typ2->decl_type != TYPE_ARRAY ) { ret_val = PW; while( typ1->decl_type == TYPE_POINTER ) { typ1 = SkipTypeFluff( typ1->object ); ++ptr_indir_level; } } else if( typ2->decl_type == TYPE_POINTER && typ1->decl_type != TYPE_ARRAY ) { ret_val = PW; while( typ2->decl_type == TYPE_POINTER ) { typ2 = SkipTypeFluff( typ2->object ); ++ptr_indir_level; } } } } if( typ1->decl_type == typ2->decl_type ) { if( typ1->decl_type == TYPE_FUNCTION ) { typ1_flags = typ1->u.fn.decl_flags; typ2_flags = typ2->u.fn.decl_flags; if( !ChkCompatibleLanguage( typ1_flags, typ2_flags ) ) { ret_val = NO; } else if( ChkCompatibleFunctionParms( typ1, typ2, false ) != TCE_OK ) { ret_val = NO; } else if( !IdenticalType( typ1->object, typ2->object ) ) { ret_val = NO; } } else if( typ1->decl_type == TYPE_STRUCT || typ1->decl_type == TYPE_UNION ) { /* allow pointers to different structs */ /* stop this for ANSI! */ if( ( typ1 != typ2 ) ) { // Types are not the same // if extensions are enabled, then we can do a compatible struct test if( CompFlags.extensions_enabled ) { if( CompatibleStructs( typ1->u.tag, typ2->u.tag ) != OK) { if( ptr_indir_level > 0 ) { if( ret_val != PW ) { ret_val = PM; } else { ret_val = NO; } } else { ret_val = NO; } } } else { ret_val = NO; } } } else if( (TYPE_FIELD == typ1->decl_type) || (TYPE_UFIELD == typ1->decl_type) ) { if( typ2->u.f.field_width > typ1->u.f.field_width ) { ret_val = AC; } } } else if( typ1->decl_type == TYPE_UNION && ptr_indir_level > 0 ) { if( InUnion( typ1, typ2, false ) != OK ) { ret_val = NO; } else { ret_val = PM; } } else if( typ2->decl_type == TYPE_UNION && ptr_indir_level > 0 ) { if( InUnion( typ2, typ1, true ) != OK ) { ret_val = NO; } else { ret_val = PM; } } else if( typ1->decl_type == TYPE_ARRAY ) { TYPEPTR typ = typ1->object; if( !IdenticalType( typ, typ2 ) ) { ret_val = NO; SKIP_ARRAYS( typ ); if( IdenticalType( typ, typ2 ) ) { ret_val = PM; } } } else if( typ2->decl_type == TYPE_ARRAY ) { TYPEPTR typ = typ2->object; if( !IdenticalType( typ, typ1 ) ) { ret_val = NO; SKIP_ARRAYS( typ ); if( IdenticalType( typ, typ1 ) ) { ret_val = PM; } } } else if( typ1->decl_type >= TYPE_LAST_ENTRY || typ2->decl_type >= TYPE_LAST_ENTRY ) { ret_val = NO; } else if( ptr_indir_level == 0 ) { ret_val = CompTable[typ1->decl_type][typ2->decl_type]; } else { ret_val = PM; switch( typ1->decl_type ) { case TYPE_CHAR: case TYPE_SHORT: case TYPE_INT: case TYPE_LONG: case TYPE_LONG64: if( typ2->decl_type == typ1->decl_type + 1 ) { ret_val = PS; } break; case TYPE_UCHAR: case TYPE_USHORT: case TYPE_UINT: case TYPE_ULONG: case TYPE_ULONG64: if( typ2->decl_type + 1 == typ1->decl_type ) { ret_val = PS; } break; default: break; } } return( ret_val ); }
static cmp_type DoCompatibleType( TYPEPTR typ1, TYPEPTR typ2, int top_level, voidptr_cmp_type voidptr_cmp ) { cmp_type ret_val; type_modifiers typ1_flags, typ2_flags; typ1_flags = FLAG_NONE; typ2_flags = FLAG_NONE; ret_val = OK; for( ;; ) { // * [] loop typ1 = SkipTypeFluff( typ1 ); // skip typedefs, go into enum base typ2 = SkipTypeFluff( typ2 ); if( typ1 == typ2 ) break; if( typ1->decl_type != typ2->decl_type ) break; if( typ1->decl_type != TYPE_ARRAY && typ1->decl_type != TYPE_POINTER ) break; if( typ1->decl_type == TYPE_ARRAY && typ2->decl_type == TYPE_ARRAY ) { /* See C99, 6.7.5.2p5 */ if( typ1->u.array->dimension && typ2->u.array->dimension ) { if( typ1->u.array->dimension != typ2->u.array->dimension ) { ret_val = PM; } } } if( typ1->decl_type==TYPE_POINTER ) { typ1_flags = typ1->u.p.decl_flags; typ2_flags = typ2->u.p.decl_flags; if( (typ1_flags & QUAL_FLAGS)!=(typ2_flags & QUAL_FLAGS) ) { if( ret_val == OK ) { //PT is a worse case ret_val = PQ; } } if( (typ1_flags & FLAG_MEM_MODEL) != (typ2_flags & FLAG_MEM_MODEL) ) { if( ( (typ1_flags & FLAG_MEM_MODEL) != FLAG_NONE // if same as mem model ok && (typ2_flags & FLAG_MEM_MODEL) != FLAG_NONE ) || TypeSize( typ1 ) != TypeSize( typ2 ) ) { return( NO ); } } ++top_level; } typ1 = typ1->object; typ2 = typ2->object; } if( typ1 != typ2 ) { // if not equal see if diff by pointers if( typ1->decl_type == TYPE_VOID || typ2->decl_type == TYPE_VOID ) { // allow void ** with any ** (but warn about it) if( top_level==1 || !CompFlags.strict_ANSI ) { if( voidptr_cmp == VC_WARN || (top_level > 1) ) { CWarn1( WARN_PCTYPE_MISMATCH, ERR_PCTYPE_MISMATCH ); } return( ret_val ); // void * and anything * } } if( top_level > 0 ) { //for PW both types must start as pointers if( typ1->decl_type == TYPE_POINTER && typ2->decl_type != TYPE_ARRAY ) { ret_val = PW; while( typ1->decl_type == TYPE_POINTER ) { typ1 = typ1->object; typ1 = SkipTypeFluff( typ1 ); ++top_level; } } else if( typ2->decl_type == TYPE_POINTER && typ1->decl_type != TYPE_ARRAY ) { ret_val = PW; while( typ2->decl_type == TYPE_POINTER ) { typ2 = typ2->object; typ2 = SkipTypeFluff( typ2 ); ++top_level; } } } } if( typ1->decl_type==typ2->decl_type ) { if( typ1->decl_type == TYPE_FUNCTION ) { typ1_flags = typ1->u.fn.decl_flags; typ2_flags = typ2->u.fn.decl_flags; if( !ChkCompatibleLanguage( typ1_flags, typ2_flags ) ) { ret_val = NO; } else { /* check to see if the two functions have identical parameters and return types */ if( ChkCompatibleFunction( typ1, typ2, 0 ) != TC_OK || !IdenticalType( typ1->object, typ2->object ) ) { CWarn1( WARN_PCTYPE_MISMATCH, ERR_PCTYPE_MISMATCH ); } } } else if( typ1->decl_type == TYPE_STRUCT || typ1->decl_type == TYPE_UNION ) { /* 11-jul-90: allow pointers to different structs */ /* 29-oct-03: stop this for ANSI! */ if( ( typ1 != typ2 ) ) { // Types are not the same // if extensions are enabled, then we can do a compatible struct test if( CompFlags.extensions_enabled ) { if( CompatibleStructs( typ1->u.tag, typ2->u.tag ) != OK) { if( top_level > 0 ) { if( ret_val != PW ) { ret_val = PM; } else { ret_val = NO; } } else { ret_val = NO; } } } else { ret_val = NO; } } } else if( (TYPE_FIELD == typ1->decl_type) || (TYPE_UFIELD == typ1->decl_type) ) { /* CarlYoung 31-Oct-03 */ if( typ2->u.f.field_width > typ1->u.f.field_width ) { ret_val = AC; } } } else if( typ1->decl_type == TYPE_UNION && top_level > 0 ) { if( InUnion( typ1, typ2, 0 ) != OK ) { ret_val = NO; } else { ret_val = PM; } } else if( typ2->decl_type == TYPE_UNION && top_level > 0 ) { if( InUnion( typ2, typ1, 1 )!= OK ) { ret_val = NO; } else { ret_val = PM; } } else if( typ1->decl_type == TYPE_ARRAY ) { TYPEPTR typ = typ1->object; if( !IdenticalType( typ, typ2 ) ) { ret_val = NO; while( typ->decl_type == TYPE_ARRAY ) { typ = typ->object; } if( IdenticalType( typ, typ2 ) ) { ret_val = PM; } } } else if( typ2->decl_type == TYPE_ARRAY ) { TYPEPTR typ = typ2->object; if( !IdenticalType( typ, typ1 ) ) { ret_val = NO; while( typ->decl_type == TYPE_ARRAY ) { typ = typ->object; } if( IdenticalType( typ, typ1 ) ) { ret_val = PM; } } } else if( typ1->decl_type >= TYPE_LAST_ENTRY || typ2->decl_type >= TYPE_LAST_ENTRY ) { ret_val = NO; } else if( top_level == 0 ) { ret_val = CompTable[ typ1->decl_type ][ typ2->decl_type ]; } else { ret_val = NO; switch( typ1->decl_type ) { case TYPE_CHAR: case TYPE_SHORT: case TYPE_INT: case TYPE_LONG: case TYPE_LONG64: if( typ2->decl_type == typ1->decl_type+1 ) { ret_val = PS; } else if( TypeSize( typ1 ) == TypeSize( typ2 ) ) { ret_val = PM; } break; case TYPE_UCHAR: case TYPE_USHORT: case TYPE_UINT: case TYPE_ULONG: case TYPE_ULONG64: if( typ2->decl_type+1 == typ1->decl_type ) { ret_val = PS; } else if( TypeSize( typ1 ) == TypeSize( typ2 ) ) { ret_val = PM; } break; default: break; } } return( ret_val ); }