mirror of
https://github.com/byteworksinc/ORCA-C.git
synced 2025-01-02 19:29:21 +00:00
Fix type checking and result type computation for ? : operator.
This was non-standard in various ways, mainly in regard to pointer types. It has been rewritten to closely follow the specification in the C standards. Several helper functions dealing with types have been introduced. They are currently only used for ? :, but they might also be useful for other purposes. New tests are also introduced to check the behavior for the ? : operator. This fixes #35 (including the initializer-specific case).
This commit is contained in:
parent
15dc3a46c4
commit
102d6873a3
133
Expression.pas
133
Expression.pas
@ -65,6 +65,7 @@ var
|
|||||||
{----}
|
{----}
|
||||||
lastwasconst: boolean; {did the last GenerateCode result in an integer constant?}
|
lastwasconst: boolean; {did the last GenerateCode result in an integer constant?}
|
||||||
lastconst: longint; {last integer constant from GenerateCode}
|
lastconst: longint; {last integer constant from GenerateCode}
|
||||||
|
lastWasNullPtrConst: boolean; {did last GenerateCode give a null ptr const?}
|
||||||
{---------------------------------------------------------------}
|
{---------------------------------------------------------------}
|
||||||
|
|
||||||
procedure AssignmentConversion (t1, t2: typePtr; isConstant: boolean;
|
procedure AssignmentConversion (t1, t2: typePtr; isConstant: boolean;
|
||||||
@ -570,6 +571,25 @@ if tree <> nil then begin
|
|||||||
end; {DisposeTree}
|
end; {DisposeTree}
|
||||||
|
|
||||||
|
|
||||||
|
procedure ValueExpressionConversions;
|
||||||
|
|
||||||
|
{ Perform type conversions applicable to an expression used }
|
||||||
|
{ for its value. These include lvalue conversion (removing }
|
||||||
|
{ qualifiers), array-to-pointer conversion, and }
|
||||||
|
{ function-to-pointer conversion. See C17 section 6.3.2.1. }
|
||||||
|
{ }
|
||||||
|
{ variables: }
|
||||||
|
{ expressionType - set to type after conversions }
|
||||||
|
|
||||||
|
begin {ValueExpressionConversions}
|
||||||
|
expressionType := Unqualify(expressionType);
|
||||||
|
if expressionType^.kind = arrayType then
|
||||||
|
expressionType := MakePointerTo(expressionType^.aType)
|
||||||
|
else if expressionType^.kind = functionType then
|
||||||
|
expressionType := MakePointerTo(expressionType);
|
||||||
|
end; {ValueExpressionConversions}
|
||||||
|
|
||||||
|
|
||||||
procedure AssignmentConversion {t1, t2: typePtr; isConstant: boolean;
|
procedure AssignmentConversion {t1, t2: typePtr; isConstant: boolean;
|
||||||
value: longint; genCode, checkConst: boolean};
|
value: longint; genCode, checkConst: boolean};
|
||||||
|
|
||||||
@ -2772,7 +2792,7 @@ var
|
|||||||
doingScalar: boolean; {temp; for assignment operators}
|
doingScalar: boolean; {temp; for assignment operators}
|
||||||
et: baseTypeEnum; {temp storage for a base type}
|
et: baseTypeEnum; {temp storage for a base type}
|
||||||
i: integer; {loop variable}
|
i: integer; {loop variable}
|
||||||
isString: boolean; {was the ? : a string?}
|
isNullPtrConst: boolean; {is this a null pointer constant?}
|
||||||
isVolatile: boolean; {is this a volatile op?}
|
isVolatile: boolean; {is this a volatile op?}
|
||||||
lType: typePtr; {type of operands}
|
lType: typePtr; {type of operands}
|
||||||
kind: typeKind; {temp type kind}
|
kind: typeKind; {temp type kind}
|
||||||
@ -2780,6 +2800,7 @@ var
|
|||||||
t1: integer; {temporary work space label number}
|
t1: integer; {temporary work space label number}
|
||||||
tlastwasconst: boolean; {temp lastwasconst}
|
tlastwasconst: boolean; {temp lastwasconst}
|
||||||
tlastconst: longint; {temp lastconst}
|
tlastconst: longint; {temp lastconst}
|
||||||
|
tlastWasNullPtrConst: boolean; {temp lastWasNullPtrConst}
|
||||||
tp: tokenPtr; {work pointer}
|
tp: tokenPtr; {work pointer}
|
||||||
tType: typePtr; {temp type of operand}
|
tType: typePtr; {temp type of operand}
|
||||||
|
|
||||||
@ -3528,6 +3549,7 @@ var
|
|||||||
|
|
||||||
begin {GenerateCode}
|
begin {GenerateCode}
|
||||||
lastwasconst := false;
|
lastwasconst := false;
|
||||||
|
isNullPtrConst := false;
|
||||||
case tree^.token.kind of
|
case tree^.token.kind of
|
||||||
|
|
||||||
parameterOper:
|
parameterOper:
|
||||||
@ -3590,6 +3612,7 @@ case tree^.token.kind of
|
|||||||
Gen1t(pc_ldc, tree^.token.ival, cgWord);
|
Gen1t(pc_ldc, tree^.token.ival, cgWord);
|
||||||
lastwasconst := true;
|
lastwasconst := true;
|
||||||
lastconst := tree^.token.ival;
|
lastconst := tree^.token.ival;
|
||||||
|
isNullPtrConst := tree^.token.ival = 0;
|
||||||
if tree^.token.kind = intConst then
|
if tree^.token.kind = intConst then
|
||||||
expressionType := intPtr
|
expressionType := intPtr
|
||||||
else if tree^.token.kind = uintConst then
|
else if tree^.token.kind = uintConst then
|
||||||
@ -3612,6 +3635,7 @@ case tree^.token.kind of
|
|||||||
expressionType := ulongPtr;
|
expressionType := ulongPtr;
|
||||||
lastwasconst := true;
|
lastwasconst := true;
|
||||||
lastconst := tree^.token.lval;
|
lastconst := tree^.token.lval;
|
||||||
|
isNullPtrConst := tree^.token.lval = 0;
|
||||||
end; {case longConst}
|
end; {case longConst}
|
||||||
|
|
||||||
longlongConst,ulonglongConst: begin
|
longlongConst,ulonglongConst: begin
|
||||||
@ -3624,6 +3648,7 @@ case tree^.token.kind of
|
|||||||
lastwasconst := true;
|
lastwasconst := true;
|
||||||
lastconst := tree^.token.qval.lo;
|
lastconst := tree^.token.qval.lo;
|
||||||
end; {if}
|
end; {if}
|
||||||
|
isNullPtrConst := (tree^.token.qval.hi = 0) and (tree^.token.qval.lo = 0);
|
||||||
end; {case longlongConst}
|
end; {case longlongConst}
|
||||||
|
|
||||||
floatConst: begin
|
floatConst: begin
|
||||||
@ -4565,78 +4590,71 @@ case tree^.token.kind of
|
|||||||
GenerateCode(tree^.left); {evaluate the condition}
|
GenerateCode(tree^.left); {evaluate the condition}
|
||||||
CompareToZero(pc_neq);
|
CompareToZero(pc_neq);
|
||||||
GenerateCode(tree^.middle); {evaluate true expression}
|
GenerateCode(tree^.middle); {evaluate true expression}
|
||||||
|
ValueExpressionConversions;
|
||||||
lType := expressionType;
|
lType := expressionType;
|
||||||
tlastwasconst := lastwasconst;
|
tlastWasNullPtrConst := lastWasNullPtrConst;
|
||||||
tlastconst := lastconst;
|
|
||||||
GenerateCode(tree^.right); {evaluate false expression}
|
GenerateCode(tree^.right); {evaluate false expression}
|
||||||
isString := false; {handle string operands}
|
ValueExpressionConversions;
|
||||||
if lType^.kind in [arrayType,pointerType] then
|
{check, compute, and convert types}
|
||||||
if lType^.aType^.baseType = cgUByte then begin
|
if (lType^.kind = pointerType) or (expressionType^.kind = pointerType)
|
||||||
with expressionType^ do
|
then begin
|
||||||
if kind in [arrayType,pointerType] then begin
|
if tlastWasNullPtrConst then begin
|
||||||
if aType^.baseType = cgUByte then
|
if lType^.kind = scalarType then
|
||||||
isString := true
|
Gen2(pc_cnn, ord(lType^.baseType), ord(cgULong));
|
||||||
else if (kind = pointerType)
|
end {if}
|
||||||
and (CompTypes(lType,expressionType)) then
|
else if lastWasNullPtrConst then begin
|
||||||
{it's all OK}
|
if expressionType^.kind = scalarType then
|
||||||
else
|
Gen2(pc_cnv, ord(expressionType^.baseType), ord(cgULong));
|
||||||
Error(47)
|
expressionType := lType;
|
||||||
end {if}
|
end {if}
|
||||||
else if (kind = scalarType)
|
else if lType^.kind <> expressionType^.kind then {not both pointers}
|
||||||
and lastWasConst
|
Error(47)
|
||||||
and (lastConst = 0) then
|
else if IsVoid(lType^.pType) or IsVoid(expressionType^.pType) then begin
|
||||||
et := UsualBinaryConversions(lType)
|
if not looseTypeChecks then
|
||||||
{it's all OK}
|
if (lType^.pType^.kind = functionType) or
|
||||||
else
|
(expressionType^.pType^.kind = functionType) then
|
||||||
Error(47);
|
Error(47);
|
||||||
lType := voidPtrPtr;
|
expressionType := MakePointerTo(MakeQualifiedType(voidPtr,
|
||||||
expressionType := voidPtrPtr;
|
lType^.pType^.qualifiers+expressionType^.pType^.qualifiers));
|
||||||
end; {if}
|
end {else if}
|
||||||
with expressionType^ do
|
else if CompTypes(Unqualify(lType^.pType),
|
||||||
if kind in [arrayType,pointerType] then
|
Unqualify(expressionType^.pType)) then begin
|
||||||
if aType^.baseType in [cgByte,cgUByte] then begin
|
if not looseTypeChecks then
|
||||||
if kind = pointerType then begin
|
if not StrictCompTypes(Unqualify(lType^.pType),
|
||||||
if tlastwasconst and (tlastconst = 0) then
|
Unqualify(expressionType^.pType)) then
|
||||||
{it's all OK}
|
|
||||||
else if CompTypes(lType, expressionType) then
|
|
||||||
{it's all OK}
|
|
||||||
else
|
|
||||||
Error(47);
|
|
||||||
end {if}
|
|
||||||
else
|
|
||||||
Error(47);
|
Error(47);
|
||||||
et := UsualBinaryConversions(lType);
|
expressionType := MakePointerTo(MakeQualifiedType(MakeCompositeType(
|
||||||
lType := voidPtrPtr;
|
Unqualify(lType^.pType),Unqualify(expressionType^.pType)),
|
||||||
expressionType := voidPtrPtr;
|
lType^.pType^.qualifiers+expressionType^.pType^.qualifiers));
|
||||||
end; {if}
|
end {else if}
|
||||||
{generate the operation}
|
else
|
||||||
if lType^.kind in [structType, unionType, arrayType] then begin
|
Error(47);
|
||||||
|
et := cgULong;
|
||||||
|
end {if}
|
||||||
|
else if lType^.kind in [structType, unionType] then begin
|
||||||
if not CompTypes(lType, expressionType) then
|
if not CompTypes(lType, expressionType) then
|
||||||
Error(47);
|
Error(47);
|
||||||
Gen0(pc_bno);
|
et := cgULong;
|
||||||
Gen0t(pc_tri, cgULong);
|
|
||||||
end {if}
|
end {if}
|
||||||
else begin
|
else begin
|
||||||
if expressionType^.kind = pointerType then
|
if IsVoid(lType) and IsVoid(expressionType) then
|
||||||
tType := expressionType
|
|
||||||
else
|
|
||||||
tType := lType;
|
|
||||||
if (expressionType^.kind = scalarType)
|
|
||||||
and (expressionType^.baseType = cgVoid)
|
|
||||||
and (lType^.kind = scalarType)
|
|
||||||
and (lType^.baseType = cgVoid) then
|
|
||||||
et := cgVoid
|
et := cgVoid
|
||||||
else
|
else
|
||||||
et := UsualBinaryConversions(lType);
|
et := UsualBinaryConversions(lType);
|
||||||
Gen0(pc_bno);
|
|
||||||
Gen0t(pc_tri, et);
|
|
||||||
end; {else}
|
end; {else}
|
||||||
if isString then {set the type for strings}
|
{generate the operation}
|
||||||
expressionType := stringTypePtr;
|
Gen0(pc_bno);
|
||||||
|
Gen0t(pc_tri, et);
|
||||||
end; {case colonch}
|
end; {case colonch}
|
||||||
|
|
||||||
castoper: begin {(cast)}
|
castoper: begin {(cast)}
|
||||||
GenerateCode(tree^.left);
|
GenerateCode(tree^.left);
|
||||||
|
if lastWasNullPtrConst then
|
||||||
|
if expressionType^.kind = scalarType then
|
||||||
|
if tree^.castType^.kind = pointerType then
|
||||||
|
if IsVoid(tree^.castType^.pType) then
|
||||||
|
if tree^.castType^.pType^.qualifiers = [] then
|
||||||
|
isNullPtrConst := true;
|
||||||
Cast(tree^.castType);
|
Cast(tree^.castType);
|
||||||
end; {case castoper}
|
end; {case castoper}
|
||||||
|
|
||||||
@ -4646,6 +4664,7 @@ case tree^.token.kind of
|
|||||||
end; {case}
|
end; {case}
|
||||||
if doDispose then
|
if doDispose then
|
||||||
dispose(tree);
|
dispose(tree);
|
||||||
|
lastWasNullPtrConst := isNullPtrConst;
|
||||||
end; {GenerateCode}
|
end; {GenerateCode}
|
||||||
|
|
||||||
|
|
||||||
|
157
Symbol.pas
157
Symbol.pas
@ -164,6 +164,16 @@ procedure InitSymbol;
|
|||||||
{ Initialize the symbol table module }
|
{ Initialize the symbol table module }
|
||||||
|
|
||||||
|
|
||||||
|
function IsVoid (tp: typePtr): boolean;
|
||||||
|
|
||||||
|
{ Check to see if a type is void }
|
||||||
|
{ }
|
||||||
|
{ Parameters: }
|
||||||
|
{ tp - type to check }
|
||||||
|
{ }
|
||||||
|
{ Returns: True if the type is void, else false }
|
||||||
|
|
||||||
|
|
||||||
function LabelToDisp (lab: integer): integer; extern;
|
function LabelToDisp (lab: integer): integer; extern;
|
||||||
|
|
||||||
{ convert a local label number to a stack frame displacement }
|
{ convert a local label number to a stack frame displacement }
|
||||||
@ -192,6 +202,17 @@ function MakePointerTo (pType: typePtr): typePtr;
|
|||||||
{ returns: the pointer type }
|
{ returns: the pointer type }
|
||||||
|
|
||||||
|
|
||||||
|
function MakeCompositeType (t1, t2: typePtr): typePtr;
|
||||||
|
|
||||||
|
{ Make the composite type of two compatible types. }
|
||||||
|
{ See C17 section 6.2.7. }
|
||||||
|
{ }
|
||||||
|
{ parameters: }
|
||||||
|
{ t1,t2 - the input types (must be compatible) }
|
||||||
|
{ }
|
||||||
|
{ returns: pointer to the composite type }
|
||||||
|
|
||||||
|
|
||||||
function MakeQualifiedType (origType: typePtr; qualifiers: typeQualifierSet):
|
function MakeQualifiedType (origType: typePtr; qualifiers: typeQualifierSet):
|
||||||
typePtr;
|
typePtr;
|
||||||
|
|
||||||
@ -427,26 +448,6 @@ var
|
|||||||
p1, p2: parameterPtr; {for tracing parameter lists}
|
p1, p2: parameterPtr; {for tracing parameter lists}
|
||||||
pt1,pt2: typePtr; {pointer types}
|
pt1,pt2: typePtr; {pointer types}
|
||||||
|
|
||||||
|
|
||||||
function IsVoid (tp: typePtr): boolean;
|
|
||||||
|
|
||||||
{ Check to see if a type is void }
|
|
||||||
{ }
|
|
||||||
{ Parameters: }
|
|
||||||
{ tp - type to check }
|
|
||||||
{ }
|
|
||||||
{ Returns: True if the type is void, else false }
|
|
||||||
|
|
||||||
begin {IsVoid}
|
|
||||||
IsVoid := false;
|
|
||||||
if tp = voidPtr then
|
|
||||||
IsVoid := true
|
|
||||||
else if tp^.kind = scalarType then
|
|
||||||
if tp^.baseType = cgVoid then
|
|
||||||
IsVoid := true;
|
|
||||||
end; {IsVoid}
|
|
||||||
|
|
||||||
|
|
||||||
begin {CompTypes}
|
begin {CompTypes}
|
||||||
CompTypes := false; {assume the types are not compatible}
|
CompTypes := false; {assume the types are not compatible}
|
||||||
kind1 := t1^.kind; {get these for efficiency}
|
kind1 := t1^.kind; {get these for efficiency}
|
||||||
@ -1703,6 +1704,122 @@ constCharPtr^.qualifiers := [tqConst];
|
|||||||
end; {InitSymbol}
|
end; {InitSymbol}
|
||||||
|
|
||||||
|
|
||||||
|
function IsVoid {tp: typePtr): boolean};
|
||||||
|
|
||||||
|
{ Check to see if a type is void }
|
||||||
|
{ }
|
||||||
|
{ Parameters: }
|
||||||
|
{ tp - type to check }
|
||||||
|
{ }
|
||||||
|
{ Returns: True if the type is void, else false }
|
||||||
|
|
||||||
|
begin {IsVoid}
|
||||||
|
IsVoid := false;
|
||||||
|
if tp = voidPtr then
|
||||||
|
IsVoid := true
|
||||||
|
else if tp^.kind = scalarType then
|
||||||
|
if tp^.baseType = cgVoid then
|
||||||
|
IsVoid := true;
|
||||||
|
end; {IsVoid}
|
||||||
|
|
||||||
|
|
||||||
|
function CopyType (tp: typePtr): typePtr;
|
||||||
|
|
||||||
|
{ Make a new copy of a type, so it can be modified. }
|
||||||
|
{ }
|
||||||
|
{ Parameters: }
|
||||||
|
{ tp - type to copy }
|
||||||
|
{ }
|
||||||
|
{ Returns: The new copy of the type }
|
||||||
|
|
||||||
|
var
|
||||||
|
tType: typePtr; {the new copy of the type}
|
||||||
|
p1,p2: parameterPtr; {parameter ptrs for copying prototypes}
|
||||||
|
pPtr: ^parameterPtr; {temp for copying prototypes}
|
||||||
|
|
||||||
|
begin {CopyType}
|
||||||
|
if tp^.kind in [structType,unionType] then
|
||||||
|
Error(57);
|
||||||
|
tType := pointer(Malloc(sizeof(typeRecord)));
|
||||||
|
tType^ := tp^; {copy type record}
|
||||||
|
tType^.saveDisp := 0;
|
||||||
|
if tp^.kind = functionType then {copy prototype parameter list}
|
||||||
|
if tp^.prototyped then begin
|
||||||
|
p1 := tp^.parameterList;
|
||||||
|
pPtr := @tType^.parameterList;
|
||||||
|
while p1 <> nil do begin
|
||||||
|
p2 := pointer(Malloc(sizeof(parameterRecord)));
|
||||||
|
p2^ := p1^;
|
||||||
|
pPtr^ := p2;
|
||||||
|
pPtr := @p2^.next;
|
||||||
|
p1 := p1^.next;
|
||||||
|
end; {while}
|
||||||
|
end; {if}
|
||||||
|
CopyType := tType;
|
||||||
|
end; {CopyType}
|
||||||
|
|
||||||
|
|
||||||
|
function MakeCompositeType {t1, t2: typePtr): typePtr};
|
||||||
|
|
||||||
|
{ Make the composite type of two compatible types. }
|
||||||
|
{ See C17 section 6.2.7. }
|
||||||
|
{ }
|
||||||
|
{ parameters: }
|
||||||
|
{ t1,t2 - the input types (should be compatible) }
|
||||||
|
{ }
|
||||||
|
{ returns: pointer to the composite type }
|
||||||
|
|
||||||
|
var
|
||||||
|
compType: typePtr; {the composite type}
|
||||||
|
tType: typePtr; {temp type}
|
||||||
|
p1,p2: parameterPtr; {parameter ptrs for handling prototypes}
|
||||||
|
|
||||||
|
begin {MakeCompositeType}
|
||||||
|
compType := t2; {default to t2}
|
||||||
|
if t1 <> t2 then
|
||||||
|
if t1^.kind = t2^.kind then begin
|
||||||
|
if t2^.kind = functionType then {switch fn types if only t1 is prototyped}
|
||||||
|
if not t2^.prototyped then
|
||||||
|
if t1^.prototyped then begin
|
||||||
|
compType := t1;
|
||||||
|
t1 := t2;
|
||||||
|
t2 := compType;
|
||||||
|
end; {if}
|
||||||
|
{apply recursively for derived types}
|
||||||
|
if t2^.kind in [arrayType,pointerType,functionType] then begin
|
||||||
|
tType := MakeCompositeType(t1^.aType,t2^.aType);
|
||||||
|
if tType <> t2^.aType then begin
|
||||||
|
compType := CopyType(compType);
|
||||||
|
compType^.aType := tType;
|
||||||
|
end; {if}
|
||||||
|
end; {if}
|
||||||
|
if t2^.kind = arrayType then {get array size from t1 if needed}
|
||||||
|
if t2^.size = 0 then
|
||||||
|
if t1^.size <> 0 then
|
||||||
|
if t1^.aType^.size = t2^.aType^.size then begin
|
||||||
|
if compType = t2 then
|
||||||
|
compType := CopyType(t2);
|
||||||
|
CompType^.size := t1^.size;
|
||||||
|
CompType^.elements := t1^.elements;
|
||||||
|
end; {if}
|
||||||
|
if t2^.kind = functionType then {compose function parameter types}
|
||||||
|
if t1^.prototyped and t2^.prototyped then begin
|
||||||
|
if compType = t2 then
|
||||||
|
compType := CopyType(t2);
|
||||||
|
p1 := t1^.parameterList;
|
||||||
|
p2 := compType^.parameterList;
|
||||||
|
while (p1 <> nil) and (p2 <> nil) do begin
|
||||||
|
p2^.parameterType :=
|
||||||
|
MakeCompositeType(p1^.parameterType,p2^.parameterType);
|
||||||
|
p1 := p1^.next;
|
||||||
|
p2 := p2^.next;
|
||||||
|
end; {while}
|
||||||
|
end;
|
||||||
|
end; {if}
|
||||||
|
MakeCompositeType := compType;
|
||||||
|
end; {MakeCompositeType}
|
||||||
|
|
||||||
|
|
||||||
function MakePascalType {origType: typePtr): typePtr};
|
function MakePascalType {origType: typePtr): typePtr};
|
||||||
|
|
||||||
{ make a version of a type with the pascal qualifier applied }
|
{ make a version of a type with the pascal qualifier applied }
|
||||||
|
@ -28,3 +28,4 @@
|
|||||||
{1} c11sassert.c
|
{1} c11sassert.c
|
||||||
{1} c11unicode.c
|
{1} c11unicode.c
|
||||||
{1} c11uchar.c
|
{1} c11uchar.c
|
||||||
|
{1} c11ternary.c
|
||||||
|
57
Tests/Conformance/c11ternary.c
Normal file
57
Tests/Conformance/c11ternary.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Test the ? : operator.
|
||||||
|
*
|
||||||
|
* The basic properties tested should hold back to C89,
|
||||||
|
* but a C11 feature (_Generic) is used to test them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define assert_type(e,t) (void)_Generic((e), t:(e))
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int i = 1;
|
||||||
|
long l = 2;
|
||||||
|
double d = 3;
|
||||||
|
struct S {int i;} s = {4};
|
||||||
|
const struct S t = {5};
|
||||||
|
const void *cvp = &i;
|
||||||
|
void *vp = &i;
|
||||||
|
const int *cip = &i;
|
||||||
|
volatile int *vip = 0;
|
||||||
|
int *ip = &i;
|
||||||
|
const char *ccp = 0;
|
||||||
|
int (*fp1)() = 0;
|
||||||
|
int (*fp2)(int (*)[40]) = 0;
|
||||||
|
int (*fp3)(int (*)[]) = 0;
|
||||||
|
|
||||||
|
assert_type(1?i:l, long);
|
||||||
|
assert_type(1?d:i, double);
|
||||||
|
assert_type(1?s:t, struct S);
|
||||||
|
1?(void)2:(void)3;
|
||||||
|
assert_type(1?ip:ip, int *);
|
||||||
|
assert_type(1?ip:cip, const int *);
|
||||||
|
assert_type(1?cip:ip, const int *);
|
||||||
|
assert_type(1?0:ip, int *);
|
||||||
|
assert_type(0?0LL:ip, int *);
|
||||||
|
assert_type(1?(void*)0:ip, int *);
|
||||||
|
assert_type(1?cip:0, const int *);
|
||||||
|
assert_type(1?cip:0LL, const int *);
|
||||||
|
assert_type(1?cip:(char)0.0, const int *);
|
||||||
|
assert_type(1?cip:(void*)0, const int *);
|
||||||
|
assert_type(1?(void*)(void*)0:ip, void *);
|
||||||
|
assert_type(1?(void*)ip:ip, void *);
|
||||||
|
assert_type(1?cip:(void*)(void*)0, const void *);
|
||||||
|
assert_type(1?(void*)ip:cip, const void *);
|
||||||
|
assert_type(1?main:main, int(*)(void));
|
||||||
|
assert_type(1?main:0, int(*)(void));
|
||||||
|
assert_type(1?(const void*)cip:(void*)ip, const void *);
|
||||||
|
assert_type(1?cvp:cip, const void *);
|
||||||
|
assert_type(1?vip:0, volatile int *);
|
||||||
|
assert_type(1?cip:vip, const volatile int *);
|
||||||
|
assert_type(1?vp:ccp, const void *);
|
||||||
|
assert_type(1?ip:cip, const int *);
|
||||||
|
assert_type(1?vp:ip, void *);
|
||||||
|
assert_type(1?fp1:fp2, int (*)(int (*)[40]));
|
||||||
|
assert_type(1?fp2:fp3, int (*)(int (*)[40]));
|
||||||
|
assert_type(1?fp2:0, int (*)(int (*)[40]));
|
||||||
|
assert_type(1?fp2:(void*)0, int (*)(int (*)[40]));
|
||||||
|
}
|
27
Tests/Deviance/D7.8.0.1.CC
Normal file
27
Tests/Deviance/D7.8.0.1.CC
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* Deviance Test 7.8.0.1: Ensure invalid operand types for ?: are detected */
|
||||||
|
|
||||||
|
int printf(const char *, ...);
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int i = 1;
|
||||||
|
struct S {int i;} s = {4};
|
||||||
|
int *ip = &i;
|
||||||
|
long *lp = 0;
|
||||||
|
const int *cip = &i;
|
||||||
|
|
||||||
|
/* each statement below should give an error */
|
||||||
|
1 ? i : s;
|
||||||
|
1 ? s : i;
|
||||||
|
1 ? i : (void)0;
|
||||||
|
1 ? ip : lp;
|
||||||
|
|
||||||
|
/* these are illegal in standard C, but allowed by loose type checks */
|
||||||
|
#pragma ignore 24
|
||||||
|
1 ? main : (void*)(void*)0;
|
||||||
|
1 ? &ip : &cip;
|
||||||
|
|
||||||
|
/* should give an error, but currently does not in ORCA/C */
|
||||||
|
1 ? cip : (char)+0.0;
|
||||||
|
|
||||||
|
printf ("Failed Deviance Test 7.8.0.1\n");
|
||||||
|
}
|
@ -51,6 +51,7 @@
|
|||||||
{1} D7.6.6.1.CC
|
{1} D7.6.6.1.CC
|
||||||
{1} D7.6.7.1.CC
|
{1} D7.6.7.1.CC
|
||||||
{1} D7.6.8.1.CC
|
{1} D7.6.8.1.CC
|
||||||
|
{1} D7.8.0.1.CC
|
||||||
{1} D8.7.0.1.CC
|
{1} D8.7.0.1.CC
|
||||||
{1} D8.8.0.1.CC
|
{1} D8.8.0.1.CC
|
||||||
{1} D9.2.0.1.CC
|
{1} D9.2.0.1.CC
|
||||||
|
6
cc.notes
6
cc.notes
@ -584,7 +584,7 @@ First, setting bit 5 causes pointer assignments that discard type qualifiers to
|
|||||||
|
|
||||||
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.
|
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 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.
|
Third, setting bit 5 causes certain comparisons involving pointers, as well as certain uses of the ? : operator with pointer operands, 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 ORCA/C to treat basic types with the same representation as mutually compatible. This affects the following pairs of types: short and int, unsigned short and unsigned int, char and unsigned char. Historically, ORCA/C essentially treated each of these pairs as being the same type, so it never reported type conflicts between them. If bit 5 is set, it will continue to do so. If bit 5 is clear, it will treat all of the above types as distinct and mutually incompatible, as specified by the C standards.
|
Fourth, setting bit 5 causes ORCA/C to treat basic types with the same representation as mutually compatible. This affects the following pairs of types: short and int, unsigned short and unsigned int, char and unsigned char. Historically, ORCA/C essentially treated each of these pairs as being the same type, so it never reported type conflicts between them. If bit 5 is set, it will continue to do so. If bit 5 is clear, it will treat all of the above types as distinct and mutually incompatible, as specified by the C standards.
|
||||||
|
|
||||||
@ -1825,6 +1825,10 @@ int foo(int[42]);
|
|||||||
|
|
||||||
(Devin Reade)
|
(Devin Reade)
|
||||||
|
|
||||||
|
189. Some combinations of operand types were not properly supported for the ? : operator. This could result in a spurious error, or could cause the ? : expression to have an incorrect type. One case where a spurious error would be produced is for expressions like i?0:p, where p is a pointer.
|
||||||
|
|
||||||
|
(Jay Krell, Devin Reade)
|
||||||
|
|
||||||
-- Bugs from C 2.1.0 that have been fixed -----------------------------------
|
-- Bugs from C 2.1.0 that have been fixed -----------------------------------
|
||||||
|
|
||||||
1. In some situations, fread() reread the first 1K or so of the file.
|
1. In some situations, fread() reread the first 1K or so of the file.
|
||||||
|
Loading…
Reference in New Issue
Block a user