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