From a8682e28d3228d58d20e34ea65b41500df8112cf Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Thu, 9 Sep 2021 21:39:29 -0500 Subject: [PATCH] Give an error for pointer assignments that discard qualifiers. This is controlled by #pragma ignore bit 5, which is now a more general "loose type checks" bit. --- Expression.pas | 14 ++++++++++---- Header.pas | 4 ++-- Scanner.pas | 9 +++++---- Symbol.pas | 2 +- cc.notes | 10 +++++++--- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Expression.pas b/Expression.pas index 1bf1390..d12bdb1 100644 --- a/Expression.pas +++ b/Expression.pas @@ -633,12 +633,18 @@ else if kind2 in pointerType: begin if kind2 = pointerType then begin if not CompTypes(t1, t2) then - Error(47); + Error(47) + else if not looseTypeChecks then + if not (t1^.ptype^.qualifiers >= t2^.ptype^.qualifiers) then + Error(163); end {if} else if kind2 = arrayType then begin - if not CompTypes(t1^.ptype, t2^.atype) then - if t1^.ptype^.baseType <> cgVoid then - Error(47); + if not CompTypes(t1^.ptype, t2^.atype) and + (t1^.ptype^.baseType <> cgVoid) then + Error(47) + else if not looseTypeChecks then + if not (t1^.ptype^.qualifiers >= t2^.atype^.qualifiers) then + Error(163); end {if} else if kind2 = scalarType then begin if isConstant and (value = 0) then begin diff --git a/Header.pas b/Header.pas index 554ef30..c887e26 100644 --- a/Header.pas +++ b/Header.pas @@ -877,7 +877,7 @@ procedure EndInclude {chPtr: ptr}; | (ord(allowTokensAfterEndif) << 2) | (ord(allowSlashSlashComments) << 3) | (ord(allowMixedDeclarations) << 4) - | (ord(looseCharTypeChecks) << 5)); + | (ord(looseTypeChecks) << 5)); p_segment: begin for i := 1 to 10 do begin @@ -1537,7 +1537,7 @@ var allowSlashSlashComments := odd(i >> 3); allowMixedDeclarations := odd(i >> 4); c99Scope := allowMixedDeclarations; - looseCharTypeChecks := odd(i >> 5); + looseTypeChecks := odd(i >> 5); end; p_segment: begin diff --git a/Scanner.pas b/Scanner.pas index cb1c19f..b874d05 100644 --- a/Scanner.pas +++ b/Scanner.pas @@ -89,7 +89,7 @@ var {Note: The following two are set together} allowMixedDeclarations: boolean; {allow mixed declarations & stmts (C99)?} c99Scope: boolean; {follow C99 rules for block scopes?} - looseCharTypeChecks: boolean; {treat char and unsigned char as compatible?} + looseTypeChecks: boolean; {loosen some standard type checks?} {---------------------------------------------------------------} @@ -719,6 +719,7 @@ if list or (numErr <> 0) then begin 160: msg := @'no matching association in _Generic expression'; 161: msg := @'illegal operator in a constant expression'; 162: msg := @'invalid escape sequence'; + 163: msg := @'pointer assignment discards qualifier(s)'; otherwise: Error(57); end; {case} writeln(msg^); @@ -3077,7 +3078,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin { 4 - allow tokens after #endif } { 8 - allow // comments } { 16 - allow mixed decls & use C99 scope rules } - { 32 - treat char and unsigned char as compatible } + { 32 - loosen some standard type checks } FlagPragmas(p_ignore); NumericDirective; if expressionType^.kind = scalarType then @@ -3089,7 +3090,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin allowTokensAfterEndif := odd(val >> 2); allowSlashSlashComments := odd(val >> 3); allowMixedDeclarations := odd(val >> 4); - looseCharTypeChecks := odd(val >> 5); + looseTypeChecks := odd(val >> 5); if allowMixedDeclarations <> c99Scope then begin if doingFunction then Error(126) @@ -3875,7 +3876,7 @@ allowTokensAfterEndif := false; {allow tokens after #endif} allowSlashSlashComments := true; {allow // comments} allowMixedDeclarations := true; {allow mixed declarations & stmts (C99)} c99Scope := true; {follow C99 rules for block scopes} -looseCharTypeChecks := true; {make char and unsigned char compatible} +looseTypeChecks := true; {loosen some standard type checks} foundFunction := false; {no functions found so far} fileList := nil; {no included files} gettingFileName := false; {not in GetFileName} diff --git a/Symbol.pas b/Symbol.pas index 5dd31b1..9d60a43 100644 --- a/Symbol.pas +++ b/Symbol.pas @@ -412,7 +412,7 @@ else if kind2 = scalarType then begin CompTypes := t1^.baseType = t2^.baseType; if t1^.cType <> t2^.cType then - if not (looseCharTypeChecks + if not (looseTypeChecks and (t1^.cType in [ctChar, ctUChar]) and (t2^.cType in [ctChar, ctUChar])) then CompTypes := false; diff --git a/cc.notes b/cc.notes index 4b6f80a..33ae393 100644 --- a/cc.notes +++ b/cc.notes @@ -178,7 +178,7 @@ See "// Comments," below, for a complete description of // comments. Bit 4 controls whether C99-style scope rules are followed and whether mixed statements and declarations are allowed in blocks. See "New Language Features," below. -Bit 5 controls whether the types "char" and "unsigned char" are treated as compatible with each other. See "Additions to #pragma ignore," below. +Bit 5 controls whether type compatibility checks should strictly follow the C standards, or whether looser rules should be used in certain cases. See "Additions to #pragma ignore," below. p. 259 @@ -475,12 +475,16 @@ 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 the types "char" and "unsigned char" are treated as compatible with each other. 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: +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 two 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 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 *. */ -If bit 5 is set, it causes the "char" and "unsigned char" types to be treated as compatible for most purposes, matching ORCA/C's historical behavior and permitting code like the above example. If this bit is clear, the types will be treated as incompatible, as required by the C standards. This will make ORCA/C give a "type conflict" error for code like the example above. Currently, this bit is set by default, giving the more permissive behavior, but new code should avoid relying on this. +ORCA/C historically permitted code like the above, and when bit 5 is set it will still do so. If bit 5 is clear, it will give a "type conflict" error. (Mike Westerfield, Kelvin Sherlock, Stephen Heumann)