This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ patch] accept __null as sentinel
- From: Michael Matz <matz at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Marcus Meissner <meissner at suse dot de>
- Date: Fri, 29 Apr 2005 21:43:09 +0200 (CEST)
- Subject: [C++ patch] accept __null as sentinel
Hi,
When annotating some more headers with sentinel attributes (a very usefull
attribute to catch common mistakes calling varargs functions on 64bit
platforms) we noticed that many C++ packages break, because they use a
plain NULL as ending element and hence trigger this warning because in C++
this is no pointer.
While strictly speaking this is indeed not correct (and hence PR19542 was
closed as invalid) we invented the special __null node in C++ (to which
NULL is expanded) exactly to make it possible to write uncasted NULL and
be sure that its size is exactly as large as a pointer type. So I
consider this a QoI issue regarding the output of needless warning
messages. The change below makes the warning also recognize this special
node as a correct sentinel. As the warning is emitted in the common C/C++
code, this either would need a frontend hook for generating the warning,
or simply moving the __null node to the common code, which is easier and
cleaner IMHO.
It adds a testcase checking this. This is regtested on
{i686,x86_64,ppc,ppc64,s390,s390x,ia64}-linux and additionally in use in
our distri since some time. I would like to have this in 4.0 and trunk
(where it needs a trivial change, from "warning (" to "warning (0, ")
Ciao,
Michael.
--
Changelog:
PR c++/19542
* c-common.c (c_common_nodes_and_builtins): Create global null_node.
(check_function_sentinel): Check for null_node as valid sentinel too.
* tree.h (tree_index): Added TI_NULL.
Define null_node as global_tree[TI_NULL].
cp/Changelog:
PR c++/19542
* cp-tree.h (cp_tree_index): Remove CPTI_NULL, to be defined in C
common frontend.
Removed null_node define.
* lex.c (cxx_init): Move null_node initialisation to C common frontend.
testsuite/Changelog:
PR c++/19542
* g++.dg/warn/sentinel.C: New testcase for __null sentinels added.
*** gcc/cp/cp-tree.h.sentinel 2005-03-30 10:19:52.000000000 +0200
--- gcc/cp/cp-tree.h 2005-04-01 10:16:45.274190351 +0200
*************** enum cp_tree_index
*** 512,518 ****
CPTI_LANG_NAME_JAVA,
CPTI_EMPTY_EXCEPT_SPEC,
- CPTI_NULL,
CPTI_JCLASS,
CPTI_TERMINATE,
CPTI_CALL_UNEXPECTED,
--- 512,517 ----
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 608,616 ****
/* Exception specifier used for throw(). */
#define empty_except_spec cp_global_trees[CPTI_EMPTY_EXCEPT_SPEC]
- /* The node for `__null'. */
- #define null_node cp_global_trees[CPTI_NULL]
-
/* If non-NULL, a POINTER_TYPE equivalent to (java::lang::Class*). */
#define jclass_node cp_global_trees[CPTI_JCLASS]
--- 607,612 ----
*** gcc/cp/lex.c.sentinel 2004-11-25 13:55:47.000000000 +0100
--- gcc/cp/lex.c 2005-04-01 10:26:07.668185370 +0200
*************** cxx_init (void)
*** 348,358 ****
cxx_init_decl_processing ();
- /* Create the built-in __null node. It is important that this is
- not shared. */
- null_node = make_node (INTEGER_CST);
- TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
-
/* The fact that G++ uses COMDAT for many entities (inline
functions, template instantiations, virtual tables, etc.) mean
that it is fundamentally unreliable to try to make decisions
--- 348,353 ----
*** gcc/testsuite/g++.dg/warn/sentinel.C.sentinel 2005-04-01 10:16:45.290186926 +0200
--- gcc/testsuite/g++.dg/warn/sentinel.C 2005-04-01 10:16:45.289187140 +0200
***************
*** 0 ****
--- 1,11 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Wall" } */
+ extern void ex (int i, ...) __attribute__ ((__sentinel__(0)));
+
+ void f()
+ {
+ ex (1, 0); /* { dg-warning "missing sentinel in function call" "" } */
+ ex (1, 0L); /* { dg-warning "missing sentinel in function call" "" } */
+ ex (1, (void *)0);
+ ex (1, __null); /* { dg-bogus "sentinel" } */
+ }
*** gcc/c-common.c.sentinel 2005-03-30 10:17:03.000000000 +0200
--- gcc/c-common.c 2005-04-01 10:16:45.250195489 +0200
*************** c_common_nodes_and_builtins (void)
*** 3269,3274 ****
--- 3269,3279 ----
mudflap_init ();
main_identifier_node = get_identifier ("main");
+
+ /* Create the built-in __null node. It is important that this is
+ not shared. */
+ null_node = make_node (INTEGER_CST);
+ TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
}
/* Look up the function in built_in_decls that corresponds to DECL
*************** check_function_sentinel (tree attrs, tre
*** 5115,5122 ****
}
/* Validate the sentinel. */
! if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
! || !integer_zerop (TREE_VALUE (sentinel)))
warning ("missing sentinel in function call");
}
}
--- 5120,5132 ----
}
/* Validate the sentinel. */
! if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
! || !integer_zerop (TREE_VALUE (sentinel)))
! /* Although __null (in C++) is only an integer we allow it
! nevertheless, as we are guaranteed that it's exactly
! as wide as a pointer, and we don't want to force
! users to cast the NULL they have written there. */
! && null_node != TREE_VALUE (sentinel))
warning ("missing sentinel in function call");
}
}
*** gcc/tree.h.sentinel 2005-03-17 07:56:14.000000000 +0100
--- gcc/tree.h 2005-04-01 10:16:45.256194204 +0200
*************** enum tree_index
*** 2595,2600 ****
--- 2595,2602 ----
TI_MAIN_IDENTIFIER,
+ TI_NULL,
+
TI_MAX
};
*************** extern GTY(()) tree global_trees[TI_MAX]
*** 2671,2676 ****
--- 2673,2681 ----
#define main_identifier_node global_trees[TI_MAIN_IDENTIFIER]
#define MAIN_NAME_P(NODE) (IDENTIFIER_NODE_CHECK (NODE) == main_identifier_node)
+ /* The node for C++ `__null'. */
+ #define null_node global_trees[TI_NULL]
+
/* An enumeration of the standard C integer types. These must be
ordered so that shorter types appear before longer ones, and so
that signed types appear before unsigned ones, for the correct