From 79f925ed078e633914daa2ba9e23b9a827d89264 Mon Sep 17 00:00:00 2001 From: jsm28 Date: Sun, 4 Dec 2005 23:04:59 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@108022 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 6 ++++ gcc/c-typeck.c | 50 +++++++++++++++++++++------------ gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.dg/c90-const-expr-5.c | 39 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c99-const-expr-5.c | 39 +++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c90-const-expr-5.c create mode 100644 gcc/testsuite/gcc.dg/c99-const-expr-5.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 31ac760..15da7d4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 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. (c_common_truthvalue_conversion): Handle NOP_EXPR the same as CONVERT_EXPR. diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index e4e21dc..36c9bc0 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 93e36dc..fb0d84d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 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. 2005-12-04 Roger Sayle 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 0000000..132932b --- /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 0000000..e7fdf2c --- /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" } */ +} -- 2.7.4