static typecheck_err ChkCompatibleFunctionParms( TYPEPTR typ1, TYPEPTR typ2, bool topLevelCheck ) { TYPEPTR *plist1; TYPEPTR *plist2; TYPEPTR p1; TYPEPTR p2; int parmno; typecheck_err rc; rc = TCE_OK; /* indicate functions are compatible */ plist1 = typ1->u.fn.parms; plist2 = typ2->u.fn.parms; if( plist1 != plist2 ) { if( plist1 == NULL ) { plist1 = plist2; plist2 = NULL; } if( plist2 == NULL ) { for( parmno = 1; (p1 = *plist1++) != NULL; ++parmno ) { if( p1->decl_type == TYPE_DOT_DOT_DOT ) { break; } if( !ChkParmPromotion( p1 ) ) { if( topLevelCheck ) { CErr2( ERR_PARM_TYPE_MISMATCH, parmno ); } rc = TCE_TYPE_MISMATCH; } } } else { p1 = *plist1++; p2 = *plist2++; for( parmno = 1; p1 != NULL && p2 != NULL; ++parmno ) { if( p1->decl_type == TYPE_DOT_DOT_DOT || p2->decl_type == TYPE_DOT_DOT_DOT ) { break; } if( !IdenticalType( p1, p2 ) ) { if( topLevelCheck ) { SetDiagType2( p1, p2 ); CErr2( ERR_PARM_TYPE_MISMATCH, parmno ); SetDiagPop(); } rc = TCE_TYPE_MISMATCH; } p1 = *plist1++; p2 = *plist2++; } if( p1 != NULL && p1->decl_type == TYPE_DOT_DOT_DOT || p2 != NULL && p2->decl_type == TYPE_DOT_DOT_DOT ) { p1 = NULL; p2 = NULL; } if( p1 != NULL || p2 != NULL ) { if( topLevelCheck ) { CErr1( ERR_PARM_COUNT_MISMATCH ); } rc = TCE_PARM_COUNT_MISMATCH; } } } return( rc ); }
static cmp_type InUnion( TYPEPTR typ1, TYPEPTR typ2, bool reversed ) { FIELDPTR field; /* typ1->decl_type == TYPE_UNION */ if( typ2->decl_type == TYPE_UNION ) return( NO ); for( field = typ1->u.tag->u.field_list; field != NULL; field = field->next_field ) { if( reversed ) { if( IdenticalType( typ2, field->field_type ) ) { return( OK ); } } else { if( IdenticalType( field->field_type, typ2 ) ) { return( OK ); } } } return( NO ); }
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 ); }
int ChkCompatibleFunction( TYPEPTR typ1, TYPEPTR typ2, int topLevelCheck ) { TYPEPTR *plist1; TYPEPTR *plist2; int parm_count; plist1 = typ1->u.fn.parms; plist2 = typ2->u.fn.parms; if( plist1 != plist2 ) { if( plist1 == NULL ) { return( ChkParmPromotion( plist2, topLevelCheck ) ); } else if( plist2 == NULL ) { return( ChkParmPromotion( plist1, topLevelCheck ) ); } parm_count = 1; for( ;; ) { if( *plist1 == NULL && *plist2 == NULL ) break; if( *plist1 == NULL || *plist2 == NULL ) { if( topLevelCheck ) { CErr1( ERR_PARM_COUNT_MISMATCH ); } return( TC_PARM_COUNT_MISMATCH ); } if( ! IdenticalType( *plist1, *plist2 ) ) { if( topLevelCheck ) { SetDiagType2( *plist1, *plist2 ); CErr2( ERR_PARM_TYPE_MISMATCH, parm_count ); SetDiagPop(); } return( TC_PARM_TYPE_MISMATCH + parm_count ); } ++plist1; ++plist2; ++parm_count; } } return( TC_OK ); /* indicate functions are compatible */ }
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 ); }