diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 31ac7608d96..15da7d4a142 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2005-12-04 Joseph S. Myers + + * 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 * c-common.c (binary_op_error): Do not allow NOP_EXPR. diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index e4e21dc101d..36c9bc0702c 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -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 %" " 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 %" " 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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 93e36dc12bc..fb0d84d7141 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2005-12-04 Joseph S. Myers + + * gcc.dg/c90-const-expr-5.c, gcc.dg/c99-const-expr-5.c: New tests. + 2005-12-04 Joseph S. Myers * gcc.dg/format/cast-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-5.c b/gcc/testsuite/gcc.dg/c90-const-expr-5.c new file mode 100644 index 00000000000..132932b565a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-const-expr-5.c @@ -0,0 +1,39 @@ +/* Test null pointer constants: typedefs for void should be OK but not + qualified void. */ +/* Origin: Joseph Myers */ +/* { 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" } */ +} diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-5.c b/gcc/testsuite/gcc.dg/c99-const-expr-5.c new file mode 100644 index 00000000000..e7fdf2c644b --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-const-expr-5.c @@ -0,0 +1,39 @@ +/* Test null pointer constants: typedefs for void should be OK but not + qualified void. */ +/* Origin: Joseph Myers */ +/* { 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" } */ +}