static cmp_type CompatibleStructs( TAGPTR tag1, TAGPTR tag2 ) { FIELDPTR field1; FIELDPTR field2; TYPEPTR typ1; TYPEPTR typ2; if( tag1 == tag2 ) return( OK ); if( tag1->size != tag2->size ) return( NO ); field1 = tag1->u.field_list; field2 = tag2->u.field_list; /* if either struct is undefined, let's be conservative */ if( (field1 == NULL) || (field2 == NULL) ) return( NO ); for( ;; ) { if( field1 == NULL ) break; if( field2 == NULL ) break; typ1 = field1->field_type; SKIP_TYPEDEFS( typ1 ); typ2 = field2->field_type; SKIP_TYPEDEFS( typ2 ); if( !IdenticalType( typ1, typ2 ) ) { if( ( typ1->decl_type == TYPE_STRUCT && typ2->decl_type == TYPE_STRUCT ) || ( typ1->decl_type == TYPE_UNION && typ2->decl_type == TYPE_UNION ) ) { if( CompatibleStructs( typ1->u.tag, typ2->u.tag ) != OK ) { return( NO ); } } else { /* 11-jul-90 */ return( NO ); } } field1 = field1->next_field; field2 = field2->next_field; } /* one list longer than other (possible with -zp4) */ if( field1 != NULL || field2 != NULL ) return( NO ); return( OK ); }
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 ); }