189 lines · c
1// RUN: %clang_cc1 -verify -ffreestanding -Wno-unused -std=c2x %s2 3/* WG14 N3042: full4 * Introduce the nullptr constant5 */6 7#include <stddef.h>8 9// FIXME: The paper calls for a feature testing macro to be added to stddef.h10// which we do not implement. This should be addressed after WG14 has processed11// national body comments for C2x as we've asked for the feature test macros to12// be removed.13#ifndef __STDC_VERSION_STDDEF_H__14#error "no version macro for stddef.h"15#endif16// expected-error@-2 {{"no version macro for stddef.h"}}17 18void questionable_behaviors() {19 nullptr_t val;20 21 // This code is intended to be rejected by C and is accepted by C++. We filed22 // an NB comment asking for this to be changed, but WG14 declined.23 (void)(1 ? val : 0); // expected-error {{non-pointer operand type 'int' incompatible with nullptr}}24 (void)(1 ? nullptr : 0); // expected-error {{non-pointer operand type 'int' incompatible with nullptr}}25 26 // This code is intended to be accepted by C and is rejected by C++. We filed27 // an NB comment asking for this to be changed, but WG14 declined.28 _Bool another = val; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}29 another = val; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}30 _Bool again = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}31 again = nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}32}33 34void test() {35 // Can we declare the type?36 nullptr_t null_val;37 38 // Can we use the keyword?39 int *typed_ptr = nullptr;40 typed_ptr = nullptr;41 42 // Can we use the keyword with the type?43 null_val = nullptr;44 // Even initialize with it?45 nullptr_t ignore = nullptr;46 47 // Can we assign an object of the type to another object of the same type?48 null_val = null_val;49 50 // Can we assign nullptr_t objects to pointer objects?51 typed_ptr = null_val;52 53 // Can we take the address of an object of type nullptr_t?54 &null_val;55 56 // How about the null pointer named constant?57 &nullptr; // expected-error {{cannot take the address of an rvalue of type 'nullptr_t'}}58 59 // Assignment from a null pointer constant to a nullptr_t is valid.60 null_val = 0;61 null_val = (void *)0;62 63 // Assignment from a nullptr_t to a pointer is also valid.64 typed_ptr = null_val;65 void *other_ptr = null_val;66 67 // Can it be used in all the places a scalar can be used?68 if (null_val) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}69 if (!null_val) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}70 for (;null_val;) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}71 while (nullptr) {} // expected-warning {{implicit conversion of nullptr constant to 'bool'}}72 null_val && nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}} \73 expected-warning {{implicit conversion of nullptr constant to 'bool'}}74 nullptr || null_val; // expected-warning {{implicit conversion of nullptr constant to 'bool'}} \75 expected-warning {{implicit conversion of nullptr constant to 'bool'}}76 null_val ? 0 : 1; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}77 sizeof(null_val);78 alignas(nullptr_t) int aligned;79 80 // Cast expressions have special handling for nullptr_t despite allowing81 // casts of scalar types.82 (nullptr_t)12; // expected-error {{cannot cast an object of type 'int' to 'nullptr_t'}}83 (float)null_val; // expected-error {{cannot cast an object of type 'nullptr_t' to 'float'}}84 (float)nullptr; // expected-error {{cannot cast an object of type 'nullptr_t' to 'float'}}85 (nullptr_t)(int *)12; // expected-error {{cannot cast an object of type 'int *' to 'nullptr_t'}}86 (nullptr_t)"testing"; // expected-error {{cannot cast an object of type 'char *' to 'nullptr_t'}}87 (nullptr_t)1.0f; // expected-error {{cannot cast an object of type 'float' to 'nullptr_t'}}88 (nullptr_t)'a'; // expected-error {{cannot cast an object of type 'int' to 'nullptr_t'}}89 90 (void)null_val; // ok91 (void)nullptr; // ok92 (bool)null_val; // ok93 (bool)nullptr; // ok94 (int *)null_val; // ok95 (int *)nullptr; // ok96 (nullptr_t)nullptr; // ok97 (nullptr_t)0; // ok98 (nullptr_t)(void *)0; // ok99 (nullptr_t)null_val; // ok100 101 // Can it be converted to bool with the result false (this relies on Clang102 // accepting additional kinds of constant expressions where an ICE is103 // required)?104 static_assert(!nullptr); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}105 static_assert(!null_val); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}106 static_assert(nullptr); // expected-error {{static assertion failed due to requirement 'nullptr'}} \107 expected-warning {{implicit conversion of nullptr constant to 'bool'}}108 static_assert(null_val); // expected-error {{static assertion failed due to requirement 'null_val'}} \109 expected-warning {{implicit conversion of nullptr constant to 'bool'}}110 111 // Do equality operators work as expected with it?112 static_assert(nullptr == nullptr);113 static_assert(null_val == null_val);114 static_assert(nullptr != (int*)1);115 static_assert(null_val != (int*)1);116 static_assert(nullptr == null_val);117 static_assert(nullptr == 0);118 static_assert(null_val == (void *)0);119 120 // None of the relational operators should succeed.121 (void)(null_val <= 0); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}122 (void)(null_val >= (void *)0); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}123 (void)(!(null_val < (void *)0)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}124 (void)(!(null_val > 0)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}125 (void)(nullptr <= 0); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}126 (void)(nullptr >= (void *)0); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}127 (void)(!(nullptr < (void *)0)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}128 (void)(!(nullptr > 0)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}129 (void)(null_val <= null_val); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}130 (void)(null_val >= null_val); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}131 (void)(!(null_val < null_val)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}132 (void)(!(null_val > null_val)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}133 (void)(null_val <= nullptr); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}134 (void)(null_val >= nullptr); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}135 (void)(!(null_val < nullptr)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}136 (void)(!(null_val > nullptr)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}137 (void)(nullptr <= nullptr); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}138 (void)(nullptr >= nullptr); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}139 (void)(!(nullptr < nullptr)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}140 (void)(!(nullptr > nullptr)); // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}141 142 // Do we pick the correct common type for conditional operators?143 _Generic(1 ? nullptr : nullptr, nullptr_t : 0);144 _Generic(1 ? null_val : null_val, nullptr_t : 0);145 _Generic(1 ? typed_ptr : null_val, typeof(typed_ptr) : 0);146 _Generic(1 ? null_val : typed_ptr, typeof(typed_ptr) : 0);147 _Generic(1 ? nullptr : typed_ptr, typeof(typed_ptr) : 0);148 _Generic(1 ? typed_ptr : nullptr, typeof(typed_ptr) : 0);149 150 // Same for GNU conditional operators?151 _Generic(nullptr ?: nullptr, nullptr_t : 0); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}152 _Generic(null_val ?: null_val, nullptr_t : 0); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}153 _Generic(typed_ptr ?: null_val, typeof(typed_ptr) : 0);154 _Generic(null_val ?: typed_ptr, typeof(typed_ptr) : 0); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}155 _Generic(nullptr ?: typed_ptr, typeof(typed_ptr) : 0); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}156 _Generic(typed_ptr ?: nullptr, typeof(typed_ptr) : 0);157 158 // Do we correctly issue type incompatibility diagnostics?159 int i = nullptr; // expected-error {{initializing 'int' with an expression of incompatible type 'nullptr_t'}}160 float f = nullptr; // expected-error {{initializing 'float' with an expression of incompatible type 'nullptr_t'}}161 i = null_val; // expected-error {{assigning to 'int' from incompatible type 'nullptr_t'}}162 f = null_val; // expected-error {{assigning to 'float' from incompatible type 'nullptr_t'}}163 null_val = i; // expected-error {{assigning to 'nullptr_t' from incompatible type 'int'}}164 null_val = f; // expected-error {{assigning to 'nullptr_t' from incompatible type 'float'}}165}166 167// Can we use it as a function parameter?168void null_param(nullptr_t);169 170void other_test() {171 // Can we call the function properly?172 null_param(nullptr);173 174 // We can pass any kind of null pointer constant.175 null_param((void *)0);176 null_param(0);177}178 179 180void printf(const char*, ...) __attribute__((format(printf, 1, 2)));181void format_specifiers() {182 // Don't warn when using nullptr with %p.183 printf("%p", nullptr);184}185 186// Ensure that conversion from a null pointer constant to nullptr_t is187// valid in a constant expression.188static_assert((nullptr_t){} == 0);189