Author: Aaron Ballman
Date: 2025-04-02T07:28:45-04:00
New Revision: 574e43dffd7a97d32f996df58b1787ad5158529c

URL: 
https://github.com/llvm/llvm-project/commit/574e43dffd7a97d32f996df58b1787ad5158529c
DIFF: 
https://github.com/llvm/llvm-project/commit/574e43dffd7a97d32f996df58b1787ad5158529c.diff

LOG: [C23] Allow casting from a null pointer constant to nullptr_t (#133742)

C23 allows a cast of a null pointer constant to nullptr_t. e.g.,
(nullptr_t)0 or (nullptr_t)(void *)0.

Fixes #133644

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaCast.cpp
    clang/test/C/C23/n3042.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 35658d63be55c..eb2591b287c2c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -159,6 +159,8 @@ C23 Feature Support
   which clarified that a compound literal used within a function prototype is
   treated as if the compound literal were within the body rather than at file
   scope.
+- Fixed a bug where you could not cast a null pointer constant to type
+  ``nullptr_t``. Fixes #GH133644.
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------

diff  --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index a5dbc16eaea0b..2824dfce1572c 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -3091,10 +3091,10 @@ void CastOperation::CheckCStyleCast() {
     return;
   }
 
-  // C23 6.5.4p4:
-  //   The type nullptr_t shall not be converted to any type other than void,
-  //   bool, or a pointer type. No type other than nullptr_t shall be converted
-  //   to nullptr_t.
+  // C23 6.5.5p4:
+  //   ... The type nullptr_t shall not be converted to any type other than
+  //   void, bool or a pointer type.If the target type is nullptr_t, the cast
+  //   expression shall be a null pointer constant or have type nullptr_t.
   if (SrcType->isNullPtrType()) {
     // FIXME: 6.3.2.4p2 says that nullptr_t can be converted to itself, but
     // 6.5.4p4 is a constraint check and nullptr_t is not void, bool, or a
@@ -3115,11 +3115,20 @@ void CastOperation::CheckCStyleCast() {
                                          Self.CurFPFeatureOverrides());
     }
   }
+
   if (DestType->isNullPtrType() && !SrcType->isNullPtrType()) {
-    Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast)
-        << /*type to nullptr*/ 1 << SrcType;
-    SrcExpr = ExprError();
-    return;
+    if (!SrcExpr.get()->isNullPointerConstant(Self.Context,
+                                              Expr::NPC_NeverValueDependent)) {
+      Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast)
+          << /*type to nullptr*/ 1 << SrcType;
+      SrcExpr = ExprError();
+      return;
+    }
+    // Need to convert the source from whatever its type is to a null pointer
+    // type first.
+    SrcExpr = ImplicitCastExpr::Create(Self.Context, DestType, 
CK_NullToPointer,
+                                       SrcExpr.get(), nullptr, VK_PRValue,
+                                       Self.CurFPFeatureOverrides());
   }
 
   if (DestType->isExtVectorType()) {

diff  --git a/clang/test/C/C23/n3042.c b/clang/test/C/C23/n3042.c
index 99661b1fb39eb..fdcb48eb1322a 100644
--- a/clang/test/C/C23/n3042.c
+++ b/clang/test/C/C23/n3042.c
@@ -82,8 +82,6 @@ void test() {
   (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
@@ -93,6 +91,9 @@ void test() {
   (int *)null_val;    // ok
   (int *)nullptr;     // ok
   (nullptr_t)nullptr; // ok
+  (nullptr_t)0;       // ok
+  (nullptr_t)(void *)0; // ok
+  (nullptr_t)null_val;  // 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


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to