Skip to content

Commit 3a31970

Browse files
committed
[C2x] Implement support for nullptr and nullptr_t
This introduces support for nullptr and nullptr_t in C2x mode. The proposal accepted by WG14 is: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3042.htm Note, there are quite a few incompatibilities with the C++ feature in some of the edge cases of this feature. Therefore, there are some FIXME comments in tests for testing behavior that might change after WG14 has resolved national body comments (a process we've not yet started). So this implementation might change slightly depending on the resolution of comments. This is called out explicitly in the release notes as well. Differential Revision: https://reviews.llvm.org/D135099
1 parent 1af7541 commit 3a31970

File tree

21 files changed

+481
-55
lines changed

21 files changed

+481
-55
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,32 @@ C2x Feature Support
452452
typeof(Val) OtherVal; // type is '__attribute__((address_space(1))) const _Atomic int'
453453
typeof_unqual(Val) OtherValUnqual; // type is 'int'
454454
455+
- Implemented `WG14 N3042 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3042.htm>`_,
456+
Introduce the nullptr constant. This introduces a new type ``nullptr_t``,
457+
declared in ``<stddef.h>`` which represents the type of the null pointer named
458+
constant, ``nullptr``. This constant is implicitly convertible to any pointer
459+
type and represents a type-safe null value.
460+
461+
Note, there are some known incompatibilities with this same feature in C++.
462+
The following examples were discovered during implementation and are subject
463+
to change depending on how national body comments are resolved by WG14 (C
464+
status is based on standard requirements, not necessarily implementation
465+
behavior):
466+
467+
.. code-block:: c
468+
469+
nullptr_t null_val;
470+
(nullptr_t)nullptr; // Rejected in C, accepted in C++, Clang accepts
471+
(void)(1 ? nullptr : 0); // Rejected in C, accepted in C++, Clang rejects
472+
(void)(1 ? null_val : 0); // Rejected in C, accepted in C++, Clang rejects
473+
bool b1 = nullptr; // Accepted in C, rejected in C++, Clang rejects
474+
b1 = null_val; // Accepted in C, rejected in C++, Clang rejects
475+
null_val = 0; // Rejected in C, accepted in C++, Clang rejects
476+
477+
void func(nullptr_t);
478+
func(0); // Rejected in C, accepted in C++, Clang rejects
479+
480+
455481
C++ Language Changes in Clang
456482
-----------------------------
457483
- Implemented DR692, DR1395 and DR1432. Use the ``-fclang-abi-compat=15`` option

clang/include/clang/AST/ExprCXX.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,8 @@ class CXXBoolLiteralExpr : public Expr {
761761
/// The null pointer literal (C++11 [lex.nullptr])
762762
///
763763
/// Introduced in C++11, the only literal of type \c nullptr_t is \c nullptr.
764+
/// This also implements the null pointer literal in C2x (C2x 6.4.1) which is
765+
/// intended to have the same semantics as the feature in C++.
764766
class CXXNullPtrLiteralExpr : public Expr {
765767
public:
766768
CXXNullPtrLiteralExpr(QualType Ty, SourceLocation Loc)

clang/include/clang/AST/PrettyPrinter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ struct PrintingPolicy {
6565
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
6666
SuppressTemplateArgsInCXXConstructors(false),
6767
SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
68-
Nullptr(LO.CPlusPlus11), Restrict(LO.C99), Alignof(LO.CPlusPlus11),
68+
Nullptr(LO.CPlusPlus11 || LO.C2x), NullptrTypeInNamespace(LO.CPlusPlus),
69+
Restrict(LO.C99), Alignof(LO.CPlusPlus11),
6970
UnderscoreAlignof(LO.C11), UseVoidForZeroParams(!LO.CPlusPlus),
7071
SplitTemplateClosers(!LO.CPlusPlus11), TerseOutput(false),
7172
PolishForDeclaration(false), Half(LO.Half),
@@ -196,6 +197,9 @@ struct PrintingPolicy {
196197
/// constant.
197198
unsigned Nullptr : 1;
198199

200+
/// Whether 'nullptr_t' is in namespace 'std' or not.
201+
unsigned NullptrTypeInNamespace : 1;
202+
199203
/// Whether we can use 'restrict' rather than '__restrict'.
200204
unsigned Restrict : 1;
201205

clang/include/clang/AST/Type.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2223,7 +2223,8 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
22232223
bool isObjCARCBridgableType() const;
22242224
bool isCARCBridgableType() const;
22252225
bool isTemplateTypeParmType() const; // C++ template type parameter
2226-
bool isNullPtrType() const; // C++11 std::nullptr_t
2226+
bool isNullPtrType() const; // C++11 std::nullptr_t or
2227+
// C2x nullptr_t
22272228
bool isNothrowT() const; // C++ std::nothrow_t
22282229
bool isAlignValT() const; // C++17 std::align_val_t
22292230
bool isStdByteType() const; // C++17 std::byte

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,11 @@ def warn_cxx98_compat_noexcept_expr : Warning<
702702
InGroup<CXX98Compat>, DefaultIgnore;
703703
def warn_cxx98_compat_nullptr : Warning<
704704
"'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
705+
def ext_c_nullptr : Extension<
706+
"'nullptr' is a C2x extension">, InGroup<C2x>;
707+
def warn_c17_compat_nullptr : Warning<
708+
"'nullptr' is incompatible with C standards before C2x">,
709+
InGroup<CPre2xCompat>, DefaultIgnore;
705710

706711
def warn_wrong_clang_attr_namespace : Warning<
707712
"'__clang__' is a predefined macro name, not an attribute scope specifier; "

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8694,6 +8694,9 @@ def warn_cast_function_type : Warning<
86948694
InGroup<CastFunctionType>, DefaultIgnore;
86958695
def err_cast_pointer_to_non_pointer_int : Error<
86968696
"pointer cannot be cast to type %0">;
8697+
def err_nullptr_cast : Error<
8698+
"cannot cast an object of type %select{'nullptr_t' to %1|%1 to 'nullptr_t'}0"
8699+
>;
86978700
def err_cast_to_bfloat16 : Error<"cannot type-cast to __bf16">;
86988701
def err_cast_from_bfloat16 : Error<"cannot type-cast from __bf16">;
86998702
def err_typecheck_expect_scalar_operand : Error<

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ CXX11_KEYWORD(char32_t , KEYNOMS18)
390390
CXX11_KEYWORD(constexpr , 0)
391391
CXX11_KEYWORD(decltype , 0)
392392
CXX11_KEYWORD(noexcept , 0)
393-
CXX11_KEYWORD(nullptr , 0)
393+
CXX11_KEYWORD(nullptr , KEYC2X)
394394
CXX11_KEYWORD(static_assert , KEYMSCOMPAT|KEYC2X)
395395
CXX11_KEYWORD(thread_local , KEYC2X)
396396

clang/lib/AST/Expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3930,7 +3930,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
39303930
if (getType().isNull())
39313931
return NPCK_NotNull;
39323932

3933-
// C++11 nullptr_t is always a null pointer constant.
3933+
// C++11/C2x nullptr_t is always a null pointer constant.
39343934
if (getType()->isNullPtrType())
39353935
return NPCK_CXX11_nullptr;
39363936

clang/lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3084,7 +3084,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
30843084
case Char32:
30853085
return "char32_t";
30863086
case NullPtr:
3087-
return "std::nullptr_t";
3087+
return Policy.NullptrTypeInNamespace ? "std::nullptr_t" : "nullptr_t";
30883088
case Overload:
30893089
return "<overloaded function type>";
30903090
case BoundMember:

clang/lib/Headers/stddef.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ using ::std::nullptr_t;
9797
#undef __need_NULL
9898
#endif /* defined(__need_NULL) */
9999

100+
/* FIXME: This is using the placeholder dates Clang produces for these macros
101+
in C2x mode; switch to the correct values once they've been published. */
102+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
103+
typedef typeof(nullptr) nullptr_t;
104+
#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L */
105+
100106
#if defined(__need_STDDEF_H_misc)
101107
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
102108
(defined(__cplusplus) && __cplusplus >= 201103L)

0 commit comments

Comments
 (0)