[clang] [clang][Sema] Fix crash on atomic builtins with incomplete type args (PR #96374)

Takuya Shimizu via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 24 21:31:48 PDT 2024


https://github.com/hazohelet updated https://github.com/llvm/llvm-project/pull/96374

>From a655e6beb048aa0d6bde730f586d3261e43f69a6 Mon Sep 17 00:00:00 2001
From: Takuya Shimizu <shimizu2486 at gmail.com>
Date: Sat, 22 Jun 2024 12:05:50 +0900
Subject: [PATCH 1/2] [clang][Sema] Fix crash on atomic with incomplete type
 args

---
 clang/lib/Sema/SemaChecking.cpp |  3 ++-
 clang/test/Sema/atomic-ops.c    | 30 ++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 87988519e7691..6d746481ccbb9 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4582,7 +4582,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
   }
 
   // Pointer to object of size zero is not allowed.
-  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+  if (!AtomTy->isIncompleteType() &&
+      Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
     Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
         << Ptr->getType() << 1 << Ptr->getSourceRange();
     return ExprError();
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 2024b81ce6aec..d957461b6cb75 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -671,6 +671,36 @@ void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
 
 }
 
+struct IncompleteTy IncA, IncB, IncC; // expected-error 3{{tentative definition has type 'struct IncompleteTy' that is never completed}} \
+                                      // expected-note 3{{forward declaration of 'struct IncompleteTy'}}
+void incompleteTypeArgError() {
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_load(&IncA, &IncB, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_load(&IncA, &IncB, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_load(&IncA, &IncB, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_load(&IncA, &IncB, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_load(&IncA, &IncB, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_load(&IncA, &IncB, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_store(&IncA, &IncB, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_store(&IncA, &IncB, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_store(&IncA, &IncB, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_store(&IncA, &IncB, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_store(&IncA, &IncB, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_store(&IncA, &IncB, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_relaxed, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acq_rel, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acquire, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_consume, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_release, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
+
+}
+
 void nullPointerWarning(void) {
   volatile _Atomic(int) vai;
   _Atomic(int) ai;

>From dd9bbf5992abaa5406d91f7a3063344b3d956be1 Mon Sep 17 00:00:00 2001
From: Takuya Shimizu <shimizu2486 at gmail.com>
Date: Tue, 25 Jun 2024 13:29:43 +0900
Subject: [PATCH 2/2] Use RequireCompleteType

---
 clang/docs/ReleaseNotes.rst       |  3 ++
 clang/lib/Sema/SemaChecking.cpp   |  6 ++--
 clang/test/Sema/atomic-ops.c      | 50 +++++++++++++++----------------
 clang/test/SemaCXX/atomic-ops.cpp | 15 ++++++++++
 4 files changed, 47 insertions(+), 27 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9ed3ff4507671..3f3406fd78bde 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -744,6 +744,9 @@ Bug Fixes to Compiler Builtins
 
 - Fix crash when atomic builtins are called with pointer to zero-size struct (#GH90330)
 
+- Clang now allows pointee types of atomic builtin arguments to be complete template types
+  that was not instantiated elsewhere.
+
 Bug Fixes to Attribute Support
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6d746481ccbb9..0fa990f9a7620 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4582,8 +4582,10 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
   }
 
   // Pointer to object of size zero is not allowed.
-  if (!AtomTy->isIncompleteType() &&
-      Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+  if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy,
+                          diag::err_incomplete_type))
+    return ExprError();
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
     Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
         << Ptr->getType() << 1 << Ptr->getSourceRange();
     return ExprError();
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index d957461b6cb75..9b82d82ff8269 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -672,32 +672,32 @@ void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
 }
 
 struct IncompleteTy IncA, IncB, IncC; // expected-error 3{{tentative definition has type 'struct IncompleteTy' that is never completed}} \
-                                      // expected-note 3{{forward declaration of 'struct IncompleteTy'}}
+                                      // expected-note 27{{forward declaration of 'struct IncompleteTy'}}
 void incompleteTypeArgError() {
-  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_load(&IncA, &IncB, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_load(&IncA, &IncB, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_load(&IncA, &IncB, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_load(&IncA, &IncB, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_load(&IncA, &IncB, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_load(&IncA, &IncB, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_store(&IncA, &IncB, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_store(&IncA, &IncB, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_store(&IncA, &IncB, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_store(&IncA, &IncB, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_store(&IncA, &IncB, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_store(&IncA, &IncB, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_relaxed, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acq_rel, memory_order_acq_rel); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acquire, memory_order_acquire); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_consume, memory_order_consume); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_release, memory_order_release); // expected-error {{must be a pointer to a trivially-copyable type}}
-  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-error {{must be a pointer to a trivially-copyable type}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_exchange(&IncB, &IncB, &IncC, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_load(&IncA, &IncB, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_load(&IncA, &IncB, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_load(&IncA, &IncB, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_load(&IncA, &IncB, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_load(&IncA, &IncB, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_load(&IncA, &IncB, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_store(&IncA, &IncB, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_store(&IncA, &IncB, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_store(&IncA, &IncB, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_store(&IncA, &IncB, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_store(&IncA, &IncB, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_store(&IncA, &IncB, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_relaxed, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acq_rel, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acquire, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_consume, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_release, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
+  __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}}
 
 }
 
diff --git a/clang/test/SemaCXX/atomic-ops.cpp b/clang/test/SemaCXX/atomic-ops.cpp
index 213161364f585..30d829d1e97d7 100644
--- a/clang/test/SemaCXX/atomic-ops.cpp
+++ b/clang/test/SemaCXX/atomic-ops.cpp
@@ -7,3 +7,18 @@ void PR28623() {
   void helper(char); // expected-note{{target}}
   __atomic_store_n(helper, 0, 0); // expected-error{{reference to overloaded function could not be resolved}}
 }
+
+template<typename>
+struct X {
+  char arr[1];
+};
+
+extern X<void>* p, *q;
+
+// They should be accepted.
+void f() {
+  __atomic_exchange(p, p, q, __ATOMIC_RELAXED);
+  __atomic_load(p, p, __ATOMIC_RELAXED);
+  __atomic_store(p, p, __ATOMIC_RELAXED);
+  __atomic_compare_exchange(p, p, q, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}



More information about the cfe-commits mailing list