diff --git a/Expression.pas b/Expression.pas index d12bdb1..75e7062 100644 --- a/Expression.pas +++ b/Expression.pas @@ -3337,28 +3337,59 @@ var end; {FunctionCall} - procedure CompareCompatible (var t1,t2: typePtr); + procedure CompareCompatible (var t1,t2: typePtr; equality: boolean); { Make sure that it is legal to compare t1 to t2 } + { } + { parameters: } + { t1,t2 - the types to compare } + { equality - is this for an (in)equality comparison? } begin {CompareCompatible} if (t1^.kind = functionType) or (t2^.kind = functionType) then begin if not CompTypes(t1, t2) then + Error(47) + else if not looseTypeChecks and not equality then Error(47); end {if} else if t1^.kind in [pointerType,arrayType] then begin if t2^.kind in [pointerType,arrayType] then begin - if (t1^.ptype = voidPtr) or (t2^.ptype = voidPtr) then - else if not CompTypes(t1^.ptype, t2^.ptype) then + if CompTypes(t1^.ptype, t2^.ptype) then begin + if not looseTypeChecks and not equality then + if t1^.ptype^.kind = functionType then + Error(47); + end {if} + else if (t1^.ptype^.kind=scalarType) and (t1^.ptype^.basetype=cgVoid) + then begin + if not looseTypeChecks then begin + if not equality then + Error(47) + else if (not tlastwasconst) or (tlastconst <> 0) then + if t2^.ptype^.kind = functionType then + Error(47); + end {if} + end {else if} + else if (t2^.ptype^.kind=scalarType) and (t2^.ptype^.basetype=cgVoid) + then begin + if not looseTypeChecks then begin + if not equality then + Error(47) + else if (not lastwasconst) or (lastconst <> 0) then + if t1^.ptype^.kind = functionType then + Error(47); + end {if} + end {else if} + else Error(47); t2 := ulongPtr; end {if} - else if (not lastwasconst) or (lastconst <> 0) then + else if (not lastwasconst) or (lastconst <> 0) + or (not equality and not looseTypeChecks) then Error(47); t1 := ulongPtr; end {if} else if expressionType^.kind in [pointerType,arrayType] then begin - if (not tlastwasconst) or (tlastconst <> 0) then + if (not equality) or (not tlastwasconst) or (tlastconst <> 0) then Error(47); t2 := ulongPtr; end; {else if} @@ -4269,7 +4300,7 @@ case tree^.token.kind of tlastwasconst := lastwasconst; tlastconst := lastconst; GenerateCode(tree^.right); - CompareCompatible(ltype, expressionType); + CompareCompatible(ltype, expressionType, true); if tree^.token.kind = eqeqop then Gen0t(pc_equ, UsualBinaryConversions(lType)) else @@ -4284,7 +4315,7 @@ case tree^.token.kind of GenerateCode(tree^.left); lType := expressionType; GenerateCode(tree^.right); - CompareCompatible(ltype, expressionType); + CompareCompatible(ltype, expressionType, false); if tree^.token.kind = lteqop then Gen0t(pc_leq, UsualBinaryConversions(lType)) else if tree^.token.kind = gteqop then diff --git a/cc.notes b/cc.notes index 2af217c..ed66314 100644 --- a/cc.notes +++ b/cc.notes @@ -475,13 +475,15 @@ Bit 2 (a value of 4) controls whether spurious tokens are allowed after an #endi Bit 4 (a value of 16) controls whether ORCA/C follows C99-style rules for declaration placement and block scopes. See "New Language Features," above. -Bit 5 (a value of 32) controls whether type compatibility checks should strictly follow the C standards, or whether looser rules should be used in certain cases. If this bit is set, the looser rules will be followed, matching ORCA/C's historical behavior. Bit 5 is currently set by default, but new code should avoid relying on this. There are three specific situations where bit 5 currently has an effect: +Bit 5 (a value of 32) controls whether type compatibility checks should strictly follow the C standards, or whether looser rules should be used in certain cases. If this bit is set, the looser rules will be followed, matching ORCA/C's historical behavior. Bit 5 is currently set by default, but new code should avoid relying on this. There are four specific situations where bit 5 currently has an effect: First, setting bit 5 causes pointer assignments that discard type qualifiers to be allowed. For example, this affects an assignment from an expression of type "const int *" to a variable of type "int *", because it discards the "const" qualifier from the type pointed to. These assignments are prohibited by the C standards, but ORCA/C historically allowed them. If bit 5 is set it will still allow them, but if bit 5 is clear it will give an error. Second, setting bit 5 causes type compatibility checks involving function pointers to ignore the prototyped parameter types. If bit 5 is clear, the prototyped parameter types (if available) must be compatible. -Third, setting bit 5 causes the types "char" and "unsigned char" to be treated as compatible with each other for most purposes. These types have the same representation in ORCA/C, but the C standards specify that they are nonetheless two distinct types and are not mutually compatible. Therefore, any standard-conforming C compiler should produce a diagnostic message if these two types or types derived from them are used in a situation where the types are required to be compatible, as in the following example: +Third, setting bit 5 causes certain comparisons involving pointers to be permitted even though they violate constraints specified in the C standards. If bit 5 is clear, the rules in the standards will be followed strictly. + +Fourth, setting bit 5 causes the types "char" and "unsigned char" to be treated as compatible with each other for most purposes. These types have the same representation in ORCA/C, but the C standards specify that they are nonetheless two distinct types and are not mutually compatible. Therefore, any standard-conforming C compiler should produce a diagnostic message if these two types or types derived from them are used in a situation where the types are required to be compatible, as in the following example: unsigned char uc; char *p = &uc; /* &uc has type unsigned char *, incompatible with char *. */