void CompatiblePtrType( TYPEPTR typ1, TYPEPTR typ2, TOKEN opr ) { SetDiagType3( typ1, typ2, opr ); /* Called with source, target. */ switch( CompatibleType( typ1, typ2, false, false ) ) { case PT: case PX: break; case PQ: if( !CompFlags.no_check_qualifiers ) { // else f**k em CWarn1( WARN_QUALIFIER_MISMATCH, ERR_QUALIFIER_MISMATCH ); } break; case PM: case NO: CWarn1( WARN_POINTER_TYPE_MISMATCH, ERR_POINTER_TYPE_MISMATCH ); break; case PS: CWarn1( WARN_SIGN_MISMATCH, ERR_SIGN_MISMATCH ); break; case PW: CWarn1( WARN_INCONSISTENT_INDIRECTION_LEVEL, ERR_INCONSISTENT_INDIRECTION_LEVEL ); break; case PC: CWarn1( WARN_PCTYPE_MISMATCH, ERR_PCTYPE_MISMATCH ); break; case OK: case AC: break; } SetDiagPop(); }
static void ChkUseful( void ) { if( CompFlags.useful_side_effect ) { CWarn1( WARN_USEFUL_SIDE_EFFECT, ERR_USEFUL_SIDE_EFFECT ); } else { CWarn1( WARN_MEANINGLESS, ERR_MEANINGLESS ); } }
static void AssRangeChk( TYPEPTR typ1, TREEPTR opnd2 ) { unsigned long high; if( opnd2->op.opr == OPR_PUSHINT ) { switch( typ1->decl_type ) { case TYPE_FIELD: case TYPE_UFIELD: high = 0xfffffffful >> (MAXSIZE - (typ1->u.f.field_width)); if( opnd2->op.ulong_value > high ) { if( (opnd2->op.ulong_value | (high >> 1)) != ~0UL ) { CWarn1( WARN_CONSTANT_TOO_BIG, ERR_CONSTANT_TOO_BIG ); } } break; case TYPE_CHAR: if( opnd2->op.long_value > 127 || opnd2->op.long_value < -128 ) { CWarn1( WARN_CONSTANT_TOO_BIG, ERR_CONSTANT_TOO_BIG ); } break; case TYPE_UCHAR: if( opnd2->op.ulong_value > 0xff) { if( (opnd2->op.ulong_value | (0xff >> 1)) != ~0UL ) { CWarn1( WARN_CONSTANT_TOO_BIG, ERR_CONSTANT_TOO_BIG ); } } break; case TYPE_UINT: if( sizeof( target_uint ) > 2 ) { break; } // fall throught case TYPE_USHORT: if( opnd2->op.ulong_value > 0xffff ) { if( (opnd2->op.ulong_value | (0xffff >> 1)) != ~0UL ) { CWarn1( WARN_CONSTANT_TOO_BIG, ERR_CONSTANT_TOO_BIG ); } } break; case TYPE_INT: if( sizeof( target_uint ) > 2 ) { break; } // fall throught case TYPE_SHORT: if( opnd2->op.long_value > 32767 || opnd2->op.long_value < -32768L ) { CWarn1( WARN_CONSTANT_TOO_BIG, ERR_CONSTANT_TOO_BIG ); } break; default: break; } } else if( opnd2->op.opr == OPR_PUSHFLOAT ) {
local void InitCharArray( TYPEPTR typ ) { unsigned len; STRING_LITERAL *str_lit; unsigned long size; DATA_QUAD dq; /* This function handles the initialization of statements like: */ /* char name[4] = "abcd"; */ str_lit = GetLiteral(); if( CompFlags.wide_char_string ) CErr1( ERR_TYPE_MISMATCH ); len = str_lit->length; if( typ->u.array->unspecified_dim ) typ->u.array->dimension = len; size = typ->u.array->dimension; if( len > size ) { if( (len - size) > 1 ) { CWarn1( WARN_LIT_TOO_LONG, ERR_LIT_TOO_LONG ); } str_lit->length = len = size; /* chop the string */ } dq.type = QDT_CONST; dq.flags = Q_DATA; dq.u.string_leaf = str_lit; GenDataQuad( &dq, len ); if( size > len ) { /* if array > len of literal */ ZeroBytes( size - len ); } CompFlags.non_zero_data = 1; }
local void ChkConstant( unsigned long value, unsigned long max_value ) { if( value > max_value ) { /* 13-sep-91 */ if( (value | (max_value >> 1)) != ~0UL ) { CWarn1( WARN_CONSTANT_TOO_BIG, ERR_CONSTANT_TOO_BIG ); } } }
local void WantEOL( void ) { if( CompFlags.extensions_enabled ) { if( CurToken != T_NULL && CurToken != T_EOF ) { if( NestLevel == SkipLevel ) { CWarn1( WARN_JUNK_FOLLOWS_DIRECTIVE, ERR_JUNK_FOLLOWS_DIRECTIVE ); } } } else { ChkEOL(); } }
static int tryBackSlashNewLine( void ) { int nc; // CurrChar is '\\' and SrcFile->column is up to date Blank1Count = 0; Blank2Count = 0; Tab1Count = 0; nc = getTestCharFromFile(); if( CompFlags.extensions_enabled ) { while( nc == ' ' ) { ++Blank1Count; nc = getTestCharFromFile(); } while( nc == '\t' ) { ++Tab1Count; nc = getTestCharFromFile(); } while( nc == ' ' ) { ++Blank2Count; nc = getTestCharFromFile(); } } if( nc == '\r' ) { nc = getTestCharFromFile(); } if( nc == '\n' ) { if( CompFlags.scanning_cpp_comment && NestLevel == SkipLevel ) { CWarn1( WARN_SPLICE_IN_CPP_COMMENT, ERR_SPLICE_IN_CPP_COMMENT ); } if( CompFlags.cpp_output ) { /* 30-may-95 */ if( CompFlags.in_pragma ) { CppPrtChar( '\\' ); CppPrtChar( '\n' ); } else if( CompFlags.cpp_line_wanted ) { CppPrtChar( '\n' ); } } SrcFile->src_line_cnt++; SrcFile->src_loc.line++; SrcFileLoc = SrcFile->src_loc; // SrcFile->column = 0; return( GetNextChar() ); } LastChar = nc; NextChar = getCharAfterBackSlash; return( '\\' ); }
static void CompareParms( TYPEPTR *master, TREEPTR parms, bool reverse ) { TYPEPTR typ1; int parmno; TREEPTR parm; if( reverse ) { parms = reverse_parms_tree( parms ); } typ1 = *master++; if( typ1 != NULL ) { if( typ1->decl_type == TYPE_VOID ) { /* type func(void); */ typ1 = NULL; /* indicate no parms */ } } for( parmno = 1, parm = parms; ( typ1 != NULL ) && ( parm != NULL ); parm = parm->left, ++parmno ) { SKIP_TYPEDEFS( typ1 ); // TODO is crap needed or has it been done if( typ1->decl_type == TYPE_FUNCTION ) { typ1 = PtrNode( typ1, FLAG_NONE, SEG_CODE ); } else if( typ1->decl_type == TYPE_ARRAY ) { typ1 = PtrNode( typ1->object, FLAG_WAS_ARRAY, SEG_DATA ); } /* check compatibility of parms */ ParmAsgnCheck( typ1, parm, parmno, false ); typ1 = *master++; if( typ1 != NULL && typ1->decl_type == TYPE_DOT_DOT_DOT ) { typ1 = NULL; parm = NULL; break; } } if( typ1 != NULL || parm != NULL ) { /* should both be NULL now */ #if _CPU == 386 /* can allow wrong number of parms with -3s option */ if( !CompFlags.register_conventions ) { CWarn1( WARN_PARM_COUNT_MISMATCH, ERR_PARM_COUNT_WARNING ); } else { CErr1( ERR_PARM_COUNT_MISMATCH ); } #else CErr1( ERR_PARM_COUNT_MISMATCH ); #endif } if( reverse ) { reverse_parms_tree( parms ); } }
local void InitWCharArray( TYPEPTR typ ) { unsigned len; unsigned i; STRING_LITERAL *str_lit; unsigned value; unsigned short *pwc; unsigned long size; DATA_QUAD dq; dq.type = QDT_SHORT; dq.flags = Q_DATA; /* This function handles the initialization of statements like: */ /* wchar_t name[5] = L"abcd"; */ str_lit = GetLiteral(); if( !CompFlags.wide_char_string ) CErr1( ERR_TYPE_MISMATCH ); len = str_lit->length / sizeof(unsigned short); if( typ->u.array->unspecified_dim ) { typ->u.array->dimension = len; } size = typ->u.array->dimension; if( len > size ) { if( (len - size) > 1 ) { CWarn1( WARN_LIT_TOO_LONG, ERR_LIT_TOO_LONG ); } len = size; } pwc = (unsigned short *)str_lit->literal; i = 0; while( i < len ) { value = *pwc++; if( value != 0 ) CompFlags.non_zero_data = 1; dq.u.long_values[0] = value; GenDataQuad( &dq, sizeof( target_short ) ); ++i; } if( i < size ) { ZeroBytes( (size - i) * sizeof(unsigned short) ); } FreeLiteral( str_lit ); }
/* Check parameters of function that were called before a prototype was seen */ extern void ChkCallParms( void ) { call_list *nextcall; call_list *next; for( nextcall = CallNodeList; nextcall != NULL; nextcall = next ) { TREEPTR callnode; TREEPTR callsite; SYM_ENTRY sym; TYPEPTR typ; next = nextcall->next; callnode = nextcall->callnode; if( callnode != NULL ) { callsite = callnode->left; // point to OPR_FUNCNAME node SymGet( &sym, callsite->op.u2.sym_handle ); typ = sym.sym_type; SKIP_TYPEDEFS( typ ); if( (sym.flags & SYM_TEMP) == 0 ) SetDiagSymbol( &sym, callsite->op.u2.sym_handle ); SetErrLoc( &nextcall->src_loc ); if( typ->u.fn.parms != NULL ) { CompareParms( typ->u.fn.parms, callnode->right, ParmsToBeReversed( sym.mods, NULL ) ); } else { // Unprototyped function called. Note that for indirect calls, there // is no symbol associated with the function and diagnostic information // is hence limited. if( sym.flags & SYM_TEMP ) { CWarn1( WARN_NONPROTO_FUNC_CALLED_INDIRECT, ERR_NONPROTO_FUNC_CALLED_INDIRECT ); } else { CWarn2p( WARN_NONPROTO_FUNC_CALLED, ERR_NONPROTO_FUNC_CALLED, SymName( &sym, callsite->op.u2.sym_handle ) ); } } InitErrLoc(); if( (sym.flags & SYM_TEMP) == 0 ) { SetDiagPop(); } } CMemFree( nextcall ); } }
static void DeadMsg( void ) /*************************/ { CWarn1( WARN_DEAD_CODE, ERR_DEAD_CODE ); DeadCode = 2; /* so we don't get more messages */ }
void Statement( void ) { LABEL_INDEX end_of_func_label; SYM_HANDLE func_result; TREEPTR tree; bool return_at_outer_level; bool skip_to_next_token; bool declaration_allowed; struct return_info return_info; SYM_ENTRY sym; #ifndef NDEBUG if( DebugFlag >= 1 ) { printf( "***** line %u, func=%s\n", TokenLoc.line, CurFunc->name ); PrintStats(); } #endif ++FuncCount; return_info.with = RETURN_WITH_NONE; /* indicate no return statements */ return_info.with_expr = FALSE; CompFlags.label_dropped = 0; CompFlags.addr_of_auto_taken = 0; /* 23-oct-91 */ end_of_func_label = 0; return_at_outer_level = FALSE; /* 28-feb-92 */ declaration_allowed = FALSE; DeadCode = 0; LoopDepth = 0; LabelIndex = 0; BlockStack = NULL; LoopStack = NULL; SwitchStack = NULL; #ifdef __SEH__ TryCount = -1; TryScope = -1; #endif StartNewBlock(); NextToken(); // skip over { ++SymLevel; tree = LeafNode( OPR_LABELCOUNT ); AddStmt( tree ); if( GrabLabels() == 0 ) { /* 29-nov-94 */ GetLocalVarDecls(); } func_result = MakeNewSym( &sym, 'R', CurFunc->sym_type->object, SC_AUTO ); sym.flags |= SYM_FUNC_RETURN_VAR; /* 25-oct-91 */ SymReplace( &sym, func_result ); for( ;; ) { CompFlags.pending_dead_code = 0; if( GrabLabels() == 0 && declaration_allowed && IsDeclarator( CurToken ) ) { GetLocalVarDecls(); } if( CompFlags.c99_extensions ) { declaration_allowed = TRUE; } skip_to_next_token = FALSE; switch( CurToken ) { case T_IF: StartNewBlock(); NextToken(); BlockStack->break_label = NextLabel(); JumpFalse( BracketExpr(), BlockStack->break_label ); /* 23-dec-88, only issue msg if ';' is on same line as 'if' */ if( CurToken == T_SEMI_COLON && SrcLoc.line == TokenLoc.line && SrcLoc.fno == TokenLoc.fno ) { SetErrLoc( &TokenLoc ); NextToken(); /* look ahead for else keyword */ if( CurToken != T_ELSE ) { /* 02-apr-91 */ ChkUseful(); /* 08-dec-88 */ } InitErrLoc(); break; } declaration_allowed = FALSE; continue; case T_WHILE: NewLoop(); NextToken(); BlockStack->break_label = NextLabel(); if( !JumpFalse( BracketExpr(), BlockStack->break_label ) ) { BlockStack->break_label = 0; /* 09-sep-92 */ } if( CurToken == T_SEMI_COLON ) { /* 08-dec-88 */ if( ! CompFlags.useful_side_effect ) { CWarn1( WARN_MEANINGLESS, ERR_MEANINGLESS ); } } declaration_allowed = FALSE; continue; case T_DO: NewLoop(); NextToken(); if( CurToken == T_RIGHT_BRACE ) { CErr1( ERR_STMT_REQUIRED_AFTER_DO ); break; } declaration_allowed = FALSE; continue; case T_FOR: ForStmt(); declaration_allowed = FALSE; continue; case T_SWITCH: SwitchStmt(); DeadCode = 1; declaration_allowed = FALSE; continue; case T_CASE: DeadCode = 0; CaseStmt(); declaration_allowed = FALSE; continue; case T_DEFAULT: DefaultStmt(); declaration_allowed = FALSE; continue; case T_BREAK: BreakStmt(); DeadCode = 1; if( BlockStack->block_type != T_LEFT_BRACE ) break; continue; case T_CONTINUE: ContinueStmt(); DeadCode = 1; if( BlockStack->block_type != T_LEFT_BRACE ) break; continue; #ifdef __SEH__ case T__LEAVE: case T___LEAVE: LeaveStmt(); DeadCode = 1; if( BlockStack->block_type != T_LEFT_BRACE ) break; continue; #endif case T_RETURN: ReturnStmt( func_result, &return_info ); if( BlockStack->prev_block == NULL ) { /* 28-feb-92 */ return_at_outer_level = TRUE; } MustRecog( T_SEMI_COLON ); if( SymLevel != 1 || CurToken != T_RIGHT_BRACE || BlockStack->block_type != T_LEFT_BRACE ) { if( end_of_func_label == 0 ) { end_of_func_label = NextLabel(); } Jump( end_of_func_label ); } if( BlockStack->block_type != T_LEFT_BRACE ) break; continue; case T_GOTO: GotoStmt(); if( BlockStack->block_type != T_LEFT_BRACE ) break; continue; case T_SEMI_COLON: NextToken(); if( BlockStack->block_type != T_LEFT_BRACE ) { if( CurToken == T_ELSE ) { declaration_allowed = FALSE; } break; } continue; case T_LEFT_BRACE: LeftBrace(); continue; case T_RIGHT_BRACE: if( BlockStack->block_type != T_LEFT_BRACE ) { CErr1( ERR_MISPLACED_RIGHT_BRACE ); } if( BlockStack->prev_block == NULL ) { skip_to_next_token = TRUE; } else { NextToken(); } break; case T_EXTERN: case T_STATIC: case T_AUTO: case T_REGISTER: case T_VOID: case T_CHAR: case T_SHORT: case T_INT: case T_LONG: case T_FLOAT: case T_DOUBLE: case T_SIGNED: case T_UNSIGNED: if( CompFlags.c99_extensions ) CErr1( ERR_UNEXPECTED_DECLARATION ); else CErr1( ERR_MISSING_RIGHT_BRACE ); break; case T_EOF: CErr1( ERR_MISSING_RIGHT_BRACE ); break; #ifdef __SEH__ case T__TRY: case T___TRY: TryStmt(); continue; #endif case T___ASM: AsmStmt(); continue; default: if( DeadCode == 1 ) { DeadMsg(); } StmtExpr(); if( BlockStack->block_type != T_LEFT_BRACE ) break; continue; } EndOfStmt(); if( BlockStack == NULL ) break; if( skip_to_next_token ) { NextToken(); } } /* C99 has special semantics for return value of main() */ if( CompFlags.c99_extensions && !strcmp( CurFunc->name, "main" ) ) { if( !return_at_outer_level ) { FixupC99MainReturn( func_result, &return_info ); return_at_outer_level = TRUE; } } if( !return_info.with_expr ) { /* no return values present */ if( !DeadCode && !CurFunc->naked ) { ChkRetValue(); } } else if( ! return_at_outer_level ) { /* 28-feb-92 */ if( ! DeadCode && !CurFunc->naked ) { CWarn( WARN_MISSING_RETURN_VALUE, ERR_MISSING_RETURN_VALUE, CurFunc->name ); } } if( end_of_func_label != 0 ) { DropLabel( end_of_func_label ); } DeadCode = 0; tree->op.label_count = LabelIndex; tree = LeafNode( OPR_FUNCEND ); if( !return_info.with_expr ) { tree->expr_type = NULL; tree->op.sym_handle = 0; } else { tree->op.sym_handle = func_result; SetFuncReturnNode( tree ); } AddStmt( tree ); AddSymList( CurFunc->u.func.locals ); SrcLoc = TokenLoc; FreeLabels(); if( skip_to_next_token ) { NextToken(); } if( CompFlags.generate_prototypes ) { if( DefFile == NULL ) { OpenDefFile(); } if( DefFile != NULL && CurFunc->stg_class == SC_NULL ) { /* function exported */ DumpFuncDefn(); } } if( Toggles & TOGGLE_INLINE ) { if( Inline_Threshold < NodeCount ) { CurFuncNode->op.func.flags &= ~FUNC_OK_TO_INLINE; } } if( VarParm( CurFunc ) ) { CurFuncNode->op.func.flags &= ~FUNC_OK_TO_INLINE; } NodeCount = 0; if( CompFlags.addr_of_auto_taken ) { /* 23-oct-91 */ CurFunc->flags &= ~ SYM_OK_TO_RECURSE; } }
static void CompareParms( TYPEPTR *master, TREEPTR parm, source_loc *src_loc ) { TYPEPTR typ; TYPEPTR typ2; int parm_num; cmp_type cmp; typ = *master++; if( typ != NULL ) { /* 27-feb-90 */ if( typ->decl_type == TYPE_VOID ) { /* type func(void); */ typ = NULL; /* indicate no parms */ } } parm_num = 1; while( ( typ != NULL ) && ( parm != NULL ) ) { SKIP_TYPEDEFS( typ ); // TODO is crap needed or has it been done if( typ->decl_type == TYPE_FUNCTION ) { typ = PtrNode( typ, FLAG_NONE, SEG_CODE ); } else if( typ->decl_type == TYPE_ARRAY ) { typ = PtrNode( typ->object, FLAG_WAS_ARRAY, SEG_DATA ); } typ2 = parm->expr_type; // typ2 will be NULL if parm is OPR_ERROR in which case an error // has already been generated if( typ2 != NULL ) { /* check compatibility of parms */ SetErrLoc( src_loc ); SetDiagType2 ( typ2, typ ); cmp = CompatibleType( typ, typ2, TRUE, IsNullConst( parm ) ); switch( cmp ) { case NO: case PT: case PX: case AC: CErr2( ERR_PARM_TYPE_MISMATCH, parm_num ); break; case PQ: if( !CompFlags.no_check_qualifiers ) { // else f**k em CWarn2( WARN_QUALIFIER_MISMATCH, ERR_PARM_QUALIFIER_MISMATCH, parm_num ); } break; case PM: /* 16-may-91 */ CWarn2( WARN_POINTER_TYPE_MISMATCH, ERR_PARM_POINTER_TYPE_MISMATCH, parm_num ); break; case PS: CWarn2( WARN_SIGN_MISMATCH, ERR_PARM_SIGN_MISMATCH, parm_num ); break; case PW: CWarn2( WARN_PARM_INCONSISTENT_INDIRECTION_LEVEL, ERR_PARM_INCONSISTENT_INDIRECTION_LEVEL, parm_num ); break; case PC: /* Allow only "void *p = int 0"; */ if( IsPointer( typ ) && parm->right->op.opr == OPR_PUSHINT ) { if( TypeSize(typ) != TypeSize(typ2) ) { CErr2( ERR_PARM_TYPE_MISMATCH, parm_num ); } else if( parm->right->op.ulong_value != 0 ) { CWarn1( WARN_NONPORTABLE_PTR_CONV, ERR_NONPORTABLE_PTR_CONV ); } } else { if( TypeSize(typ->object) == TypeSize(typ2->object) ) { CWarn2( WARN_POINTER_TYPE_MISMATCH, ERR_PARM_POINTER_TYPE_MISMATCH, parm_num ); } else { CErr2( ERR_PARM_TYPE_MISMATCH, parm_num ); } } break; case OK: break; } SetDiagPop(); InitErrLoc(); } typ = *master++; if( typ != NULL && typ->decl_type == TYPE_DOT_DOT_DOT ) return; parm = parm->left; ++parm_num; } if( typ != NULL || parm != NULL ) { /* should both be NULL now */ SetErrLoc( src_loc ); #if _CPU == 386 /* can allow wrong number of parms with -3s option; 06-dec-91 */ if( !CompFlags.register_conventions ) { CWarn1( WARN_PARM_COUNT_MISMATCH, ERR_PARM_COUNT_WARNING ); return; } #endif CErr1( ERR_PARM_COUNT_MISMATCH ); /* 18-feb-90 */ } }
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 ); }