aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-common.cc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2022-08-10 15:00:49 -0400
committerMarek Polacek <polacek@redhat.com>2022-08-25 17:54:13 -0400
commit60d84e82639e25b025a926b19ec5a92fba4447ce (patch)
tree7bbbeeb4ff4c16132b02c74f95a936d80cd09779 /gcc/c-family/c-common.cc
parent14cfa01755a66afbae2539f8b5796c960ddcecc6 (diff)
downloadgcc-60d84e82639e25b025a926b19ec5a92fba4447ce.zip
gcc-60d84e82639e25b025a926b19ec5a92fba4447ce.tar.gz
gcc-60d84e82639e25b025a926b19ec5a92fba4447ce.tar.bz2
c: Implement C23 nullptr (N3042)
This patch implements the C23 nullptr literal: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3042.htm> (with wording fixes from N3047), which is intended to replace the problematic definition of NULL which might be either of integer type or void*. Since C++ has had nullptr for over a decade now, it was relatively easy to just move the built-in node definitions from the C++ FE to the C/C++ common code. Also, our DWARF emitter already handles NULLPTR_TYPE by emitting DW_TAG_unspecified_type. However, I had to handle a lot of contexts such as ?:, comparison, conversion, etc. There are some minor differences, e.g. in C you can do bool b = nullptr; but in C++ you have to use direct-initialization: bool b{nullptr}; And I think that nullptr_t n = 0; is only valid in C++. Of course, C doesn't have to handle mangling, RTTI, substitution, overloading, ... This patch also defines nullptr_t in <stddef.h>. However, it does not define __STDC_VERSION_STDDEF_H__ yet, because we don't know yet what value it should be defined to. gcc/c-family/ChangeLog: * c-common.cc (c_common_reswords): Enable nullptr in C2X. (c_common_nodes_and_builtins): Create the built-in node for nullptr. * c-common.h (enum c_tree_index): Add CTI_NULLPTR, CTI_NULLPTR_TYPE. (struct c_common_resword): Resize the disable member. (D_C2X): Add. (nullptr_node): Define. (nullptr_type_node): Define. (NULLPTR_TYPE_P): Define. * c-pretty-print.cc (c_pretty_printer::simple_type_specifier): Handle NULLPTR_TYPE. (c_pretty_printer::direct_abstract_declarator): Likewise. (c_pretty_printer::constant): Likewise. gcc/c/ChangeLog: * c-convert.cc (c_convert) <case POINTER_TYPE>: Handle NULLPTR_TYPE. Give a better diagnostic when converting to nullptr_t. * c-decl.cc (c_init_decl_processing): Perform C-specific nullptr initialization. * c-parser.cc (c_parse_init): Maybe OR D_C2X into mask. (c_parser_postfix_expression): Handle RID_NULLPTR. * c-typeck.cc (null_pointer_constant_p): Return true when expr is nullptr_node. (build_unary_op) <case TRUTH_NOT_EXPR>: Handle NULLPTR_TYPE. (build_conditional_expr): Handle the case when the second/third operand is NULLPTR_TYPE and third/second operand is POINTER_TYPE. (convert_for_assignment): Handle converting an expression of type nullptr_t to pointer/bool. (build_binary_op) <case TRUTH_XOR_EXPR>: Handle NULLPTR_TYPE. <case EQ_EXPR>: Handle comparing operands of type nullptr_t. gcc/cp/ChangeLog: * cp-tree.h (enum cp_tree_index): Remove CTI_NULLPTR, CTI_NULLPTR_TYPE. Move it to c_tree_index. (nullptr_node): No longer define here. (nullptr_type_node): Likewise. (NULLPTR_TYPE_P): Likewise. * decl.cc (cxx_init_decl_processing): Only keep C++-specific nullptr initialization; move the shared code to c_common_nodes_and_builtins. gcc/ChangeLog: * ginclude/stddef.h: Define nullptr_t. gcc/testsuite/ChangeLog: * gcc.dg/c11-nullptr-1.c: New test. * gcc.dg/c17-nullptr-1.c: New test. * gcc.dg/c17-nullptr-2.c: New test. * gcc.dg/c2x-nullptr-1.c: New test. * gcc.dg/c2x-nullptr-2.c: New test. * gcc.dg/c2x-nullptr-3.c: New test. * gcc.dg/c2x-nullptr-4.c: New test. * gcc.dg/c2x-nullptr-5.c: New test.
Diffstat (limited to 'gcc/c-family/c-common.cc')
-rw-r--r--gcc/c-family/c-common.cc20
1 files changed, 17 insertions, 3 deletions
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 6e41ceb..82ebe7c 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -324,8 +324,10 @@ static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
if they match the mask.
Masks for languages:
- C --std=c89: D_C99 | D_CXXONLY | D_OBJC | D_CXX_OBJC
- C --std=c99: D_CXXONLY | D_OBJC
+ C --std=c89: D_C99 | D_C2X | D_CXXONLY | D_OBJC | D_CXX_OBJC
+ C --std=c99: D_C2X | D_CXXONLY | D_OBJC
+ C --std=c17: D_C2X | D_CXXONLY | D_OBJC
+ C --std=c2x: D_CXXONLY | D_OBJC
ObjC is like C except that D_OBJC and D_CXX_OBJC are not set
C++ --std=c++98: D_CONLY | D_CXX11 | D_CXX20 | D_OBJC
C++ --std=c++11: D_CONLY | D_CXX20 | D_OBJC
@@ -500,7 +502,7 @@ const struct c_common_resword c_common_reswords[] =
{ "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
{ "new", RID_NEW, D_CXXONLY | D_CXXWARN },
{ "noexcept", RID_NOEXCEPT, D_CXXONLY | D_CXX11 | D_CXXWARN },
- { "nullptr", RID_NULLPTR, D_CXXONLY | D_CXX11 | D_CXXWARN },
+ { "nullptr", RID_NULLPTR, D_C2X | D_CXX11 | D_CXXWARN },
{ "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN },
{ "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN },
{ "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN },
@@ -4723,6 +4725,18 @@ c_common_nodes_and_builtins (void)
null_node = make_int_cst (1, 1);
TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
+ /* Create the built-in nullptr node. This part of its initialization is
+ common to C and C++. The front ends can further adjust its definition
+ in {c,cxx}_init_decl_processing. In particular, we aren't setting the
+ alignment here for C++ backward ABI bug compatibility. */
+ nullptr_type_node = make_node (NULLPTR_TYPE);
+ TYPE_SIZE (nullptr_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
+ TYPE_SIZE_UNIT (nullptr_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
+ TYPE_UNSIGNED (nullptr_type_node) = 1;
+ TYPE_PRECISION (nullptr_type_node) = GET_MODE_BITSIZE (ptr_mode);
+ SET_TYPE_MODE (nullptr_type_node, ptr_mode);
+ nullptr_node = build_int_cst (nullptr_type_node, 0);
+
/* Since builtin_types isn't gc'ed, don't export these nodes. */
memset (builtin_types, 0, sizeof (builtin_types));
}