c-typeck.c (null_pointer_constant_p): New function.
* c-typeck.c (null_pointer_constant_p): New function. (build_conditional_expr, build_c_cast, convert_for_assignment, build_binary_op): Use it. testsuite: * gcc.dg/c90-const-expr-5.c, gcc.dg/c99-const-expr-5.c: New tests. From-SVN: r108022
This commit is contained in:
parent
1344f9a318
commit
6aa3c60d7f
@ -1,3 +1,9 @@
|
||||
2005-12-04 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* c-typeck.c (null_pointer_constant_p): New function.
|
||||
(build_conditional_expr, build_c_cast, convert_for_assignment,
|
||||
build_binary_op): Use it.
|
||||
|
||||
2005-12-04 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* c-common.c (binary_op_error): Do not allow NOP_EXPR.
|
||||
|
@ -74,6 +74,7 @@ static int missing_braces_mentioned;
|
||||
static int require_constant_value;
|
||||
static int require_constant_elements;
|
||||
|
||||
static bool null_pointer_constant_p (tree);
|
||||
static tree qualify_type (tree, tree);
|
||||
static int tagged_types_tu_compatible_p (tree, tree);
|
||||
static int comp_target_types (tree, tree);
|
||||
@ -106,6 +107,23 @@ static int lvalue_or_else (tree, enum lvalue_use);
|
||||
static int lvalue_p (tree);
|
||||
static void record_maybe_used_decl (tree);
|
||||
static int comptypes_internal (tree, tree);
|
||||
|
||||
/* Return true if EXP is a null pointer constant, false otherwise. */
|
||||
|
||||
static bool
|
||||
null_pointer_constant_p (tree expr)
|
||||
{
|
||||
/* This should really operate on c_expr structures, but they aren't
|
||||
yet available everywhere required. */
|
||||
tree type = TREE_TYPE (expr);
|
||||
return (TREE_CODE (expr) == INTEGER_CST
|
||||
&& !TREE_CONSTANT_OVERFLOW (expr)
|
||||
&& integer_zerop (expr)
|
||||
&& (INTEGRAL_TYPE_P (type)
|
||||
|| (TREE_CODE (type) == POINTER_TYPE
|
||||
&& VOID_TYPE_P (TREE_TYPE (type))
|
||||
&& TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
|
||||
}
|
||||
/* This is a cache to hold if two types are compatible or not. */
|
||||
|
||||
struct tagged_tu_seen_cache {
|
||||
@ -3205,9 +3223,9 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
||||
{
|
||||
if (comp_target_types (type1, type2))
|
||||
result_type = common_pointer_type (type1, type2);
|
||||
else if (integer_zerop (orig_op1) && TREE_TYPE (type1) == void_type_node)
|
||||
else if (null_pointer_constant_p (orig_op1))
|
||||
result_type = qualify_type (type2, type1);
|
||||
else if (integer_zerop (orig_op2) && TREE_TYPE (type2) == void_type_node)
|
||||
else if (null_pointer_constant_p (orig_op2))
|
||||
result_type = qualify_type (type1, type2);
|
||||
else if (VOID_TYPE_P (TREE_TYPE (type1)))
|
||||
{
|
||||
@ -3233,7 +3251,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
||||
}
|
||||
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
|
||||
{
|
||||
if (!integer_zerop (op2))
|
||||
if (!null_pointer_constant_p (orig_op2))
|
||||
pedwarn ("pointer/integer type mismatch in conditional expression");
|
||||
else
|
||||
{
|
||||
@ -3243,7 +3261,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
|
||||
}
|
||||
else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
|
||||
{
|
||||
if (!integer_zerop (op1))
|
||||
if (!null_pointer_constant_p (orig_op1))
|
||||
pedwarn ("pointer/integer type mismatch in conditional expression");
|
||||
else
|
||||
{
|
||||
@ -3481,7 +3499,7 @@ build_c_cast (tree type, tree expr)
|
||||
&& TREE_CODE (otype) == POINTER_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
|
||||
&& !(integer_zerop (value) && TREE_TYPE (otype) == void_type_node))
|
||||
&& !null_pointer_constant_p (value))
|
||||
pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
|
||||
|
||||
ovalue = value;
|
||||
@ -3834,7 +3852,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
||||
}
|
||||
|
||||
/* Can convert integer zero to any pointer type. */
|
||||
if (integer_zerop (rhs))
|
||||
if (null_pointer_constant_p (rhs))
|
||||
{
|
||||
rhs = null_pointer_node;
|
||||
break;
|
||||
@ -3972,7 +3990,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
||||
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
|
||||
||
|
||||
(VOID_TYPE_P (ttr)
|
||||
&& !integer_zerop (rhs)
|
||||
&& !null_pointer_constant_p (rhs)
|
||||
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
|
||||
WARN_FOR_ASSIGNMENT (G_("ISO C forbids passing argument %d of "
|
||||
"%qE between function pointer "
|
||||
@ -4062,7 +4080,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|
||||
/* An explicit constant 0 can convert to a pointer,
|
||||
or one that results from arithmetic, even including
|
||||
a cast to integer type. */
|
||||
if (!integer_zerop (rhs))
|
||||
if (!null_pointer_constant_p (rhs))
|
||||
WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
|
||||
"pointer from integer without a cast"),
|
||||
G_("assignment makes pointer from integer "
|
||||
@ -7900,14 +7918,14 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
|
||||
{
|
||||
/* op0 != orig_op0 detects the case of something
|
||||
whose value is 0 but which isn't a valid null ptr const. */
|
||||
if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
|
||||
if (pedantic && !null_pointer_constant_p (orig_op0)
|
||||
&& TREE_CODE (tt1) == FUNCTION_TYPE)
|
||||
pedwarn ("ISO C forbids comparison of %<void *%>"
|
||||
" with function pointer");
|
||||
}
|
||||
else if (VOID_TYPE_P (tt1))
|
||||
{
|
||||
if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
|
||||
if (pedantic && !null_pointer_constant_p (orig_op1)
|
||||
&& TREE_CODE (tt0) == FUNCTION_TYPE)
|
||||
pedwarn ("ISO C forbids comparison of %<void *%>"
|
||||
" with function pointer");
|
||||
@ -7920,11 +7938,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
|
||||
if (result_type == NULL_TREE)
|
||||
result_type = ptr_type_node;
|
||||
}
|
||||
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
|
||||
&& integer_zerop (op1))
|
||||
else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
|
||||
result_type = type0;
|
||||
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
|
||||
&& integer_zerop (op0))
|
||||
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
|
||||
result_type = type1;
|
||||
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
|
||||
{
|
||||
@ -7964,15 +7980,13 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
|
||||
pedwarn ("comparison of distinct pointer types lacks a cast");
|
||||
}
|
||||
}
|
||||
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
|
||||
&& integer_zerop (op1))
|
||||
else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
|
||||
{
|
||||
result_type = type0;
|
||||
if (pedantic || extra_warnings)
|
||||
pedwarn ("ordered comparison of pointer with integer zero");
|
||||
}
|
||||
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
|
||||
&& integer_zerop (op0))
|
||||
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
|
||||
{
|
||||
result_type = type1;
|
||||
if (pedantic)
|
||||
|
@ -1,3 +1,7 @@
|
||||
2005-12-04 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* gcc.dg/c90-const-expr-5.c, gcc.dg/c99-const-expr-5.c: New tests.
|
||||
|
||||
2005-12-04 Joseph S. Myers <joseph@codesourcery.com>
|
||||
|
||||
* gcc.dg/format/cast-1.c: New test.
|
||||
|
39
gcc/testsuite/gcc.dg/c90-const-expr-5.c
Normal file
39
gcc/testsuite/gcc.dg/c90-const-expr-5.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* Test null pointer constants: typedefs for void should be OK but not
|
||||
qualified void. */
|
||||
/* Origin: Joseph Myers <joseph@codesourcery.com> */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
|
||||
|
||||
typedef void V;
|
||||
int *p;
|
||||
long *q;
|
||||
int j;
|
||||
void (*fp)(void);
|
||||
|
||||
void
|
||||
f (void)
|
||||
{
|
||||
/* (V *)0 is a null pointer constant, so the assignment should be
|
||||
diagnosed. */
|
||||
q = (j ? p : (V *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
|
||||
q = (j ? p : (void *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
|
||||
/* And this conversion should be valid. */
|
||||
(void (*)(void))(V *)0;
|
||||
(void (*)(void))(void *)0;
|
||||
/* Pointers to qualified void are not valid null pointer
|
||||
constants. */
|
||||
fp = (const void *)0; /* { dg-error "error: ISO C forbids assignment between function pointer and 'void \\*'" } */
|
||||
fp = (void *)0;
|
||||
fp = (V *)0;
|
||||
fp = 0;
|
||||
fp == 0;
|
||||
0 == fp;
|
||||
fp == (void *)0;
|
||||
(void *)0 == fp;
|
||||
fp == (V *)0;
|
||||
(V *)0 == fp;
|
||||
fp == (V *)1; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
(V *)1 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
fp == (const void *)0; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
(const void *)0 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
}
|
39
gcc/testsuite/gcc.dg/c99-const-expr-5.c
Normal file
39
gcc/testsuite/gcc.dg/c99-const-expr-5.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* Test null pointer constants: typedefs for void should be OK but not
|
||||
qualified void. */
|
||||
/* Origin: Joseph Myers <joseph@codesourcery.com> */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
|
||||
|
||||
typedef void V;
|
||||
int *p;
|
||||
long *q;
|
||||
int j;
|
||||
void (*fp)(void);
|
||||
|
||||
void
|
||||
f (void)
|
||||
{
|
||||
/* (V *)0 is a null pointer constant, so the assignment should be
|
||||
diagnosed. */
|
||||
q = (j ? p : (V *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
|
||||
q = (j ? p : (void *)0); /* { dg-error "error: assignment from incompatible pointer type" } */
|
||||
/* And this conversion should be valid. */
|
||||
(void (*)(void))(V *)0;
|
||||
(void (*)(void))(void *)0;
|
||||
/* Pointers to qualified void are not valid null pointer
|
||||
constants. */
|
||||
fp = (const void *)0; /* { dg-error "error: ISO C forbids assignment between function pointer and 'void \\*'" } */
|
||||
fp = (void *)0;
|
||||
fp = (V *)0;
|
||||
fp = 0;
|
||||
fp == 0;
|
||||
0 == fp;
|
||||
fp == (void *)0;
|
||||
(void *)0 == fp;
|
||||
fp == (V *)0;
|
||||
(V *)0 == fp;
|
||||
fp == (V *)1; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
(V *)1 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
fp == (const void *)0; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
(const void *)0 == fp; /* { dg-error "error: ISO C forbids comparison of 'void \\*' with function pointer" } */
|
||||
}
|
Loading…
Reference in New Issue
Block a user