[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-04 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner created 
https://github.com/llvm/llvm-project/pull/91057

When an atomic builtin is called with a pointer to an object of size zero, an 
arithmetic exception gets thrown because there is a modulo operation with the 
objects size in codegen. This is described here: #90330

I have added a check to SemaChecking.cpp, which throws an error if this is the 
case.


From fc0588cb0d3558d518dc7d352f6590e0fbae0608 Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticFrontendKinds.td|  3 ++
 clang/lib/Sema/SemaChecking.cpp   | 12 ++-
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index fcffadacc8e631..0c50f125b8e05d 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -328,6 +328,9 @@ def warn_atomic_op_misaligned : Warning<
   "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 
bytes)">,
   InGroup;
 
+def err_atomic_op_size_zero : Error<
+  "First argument cannot be a pointer to an object of size zero">;
+
 def warn_atomic_op_oversized : Warning<
   "large atomic operation may incur "
   "significant performance penalty"
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e33113ab9c4c1d..d822fbedc9ae68 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -40,6 +40,7 @@
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -8495,7 +8496,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 << 0 << AdjustedNumArgs << static_cast(Args.size())
 << /*is non object*/ 0 << ExprRange;
 return ExprError();
-  } else if (Args.size() > AdjustedNumArgs) {
+  }
+  
+  if (Args.size() > AdjustedNumArgs) {
 Diag(Args[AdjustedNumArgs]->getBeginLoc(),
  diag::err_typecheck_call_too_many_args)
 << 0 << AdjustedNumArgs << static_cast(Args.size())
@@ -8542,6 +8545,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // pointer to object of size zero is not allowed
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_op_size_zero)
+<< Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf409..97da2582312bbb 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_release); // expected-error {{First 
argument cannot be

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-13 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From dfa0b6b840b1ab12c27b7203ab372bd147885173 Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticFrontendKinds.td|  3 ++
 clang/lib/Sema/SemaChecking.cpp   | 12 ++-
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index e456ec2cac461..74d96a8cbe0dc 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -330,6 +330,9 @@ def warn_atomic_op_misaligned : Warning<
   "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 
bytes)">,
   InGroup;
 
+def err_atomic_op_size_zero : Error<
+  "First argument cannot be a pointer to an object of size zero">;
+
 def warn_atomic_op_oversized : Warning<
   "large atomic operation may incur "
   "significant performance penalty"
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..f91ab833b4fc7 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -40,6 +40,7 @@
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -8497,7 +8498,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 << 0 << AdjustedNumArgs << static_cast(Args.size())
 << /*is non object*/ 0 << ExprRange;
 return ExprError();
-  } else if (Args.size() > AdjustedNumArgs) {
+  }
+  
+  if (Args.size() > AdjustedNumArgs) {
 Diag(Args[AdjustedNumArgs]->getBeginLoc(),
  diag::err_typecheck_call_too_many_args)
 << 0 << AdjustedNumArgs << static_cast(Args.size())
@@ -8544,6 +8547,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // pointer to object of size zero is not allowed
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_op_size_zero)
+<< Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..97da2582312bb 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_store(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atom

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-14 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From 770e7c543b0651b776b2bc23353e85a7f62a695a Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticFrontendKinds.td|  3 ++
 clang/lib/Sema/SemaChecking.cpp   | 12 ++-
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index e456ec2cac461..74d96a8cbe0dc 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -330,6 +330,9 @@ def warn_atomic_op_misaligned : Warning<
   "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 
bytes)">,
   InGroup;
 
+def err_atomic_op_size_zero : Error<
+  "First argument cannot be a pointer to an object of size zero">;
+
 def warn_atomic_op_oversized : Warning<
   "large atomic operation may incur "
   "significant performance penalty"
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..7db31c2b8c0b8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -40,6 +40,7 @@
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -8497,7 +8498,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 << 0 << AdjustedNumArgs << static_cast(Args.size())
 << /*is non object*/ 0 << ExprRange;
 return ExprError();
-  } else if (Args.size() > AdjustedNumArgs) {
+  }
+ 
+  if (Args.size() > AdjustedNumArgs) {
 Diag(Args[AdjustedNumArgs]->getBeginLoc(),
  diag::err_typecheck_call_too_many_args)
 << 0 << AdjustedNumArgs << static_cast(Args.size())
@@ -8544,6 +8547,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // pointer to object of size zero is not allowed
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_op_size_zero)
+<< Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..97da2582312bb 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_store(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomi

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-14 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From d587410660127d372fa35963dd26b97fd133d7c5 Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticFrontendKinds.td|  3 ++
 clang/lib/Sema/SemaChecking.cpp   | 11 ++-
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index e456ec2cac461..74d96a8cbe0dc 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -330,6 +330,9 @@ def warn_atomic_op_misaligned : Warning<
   "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 
bytes)">,
   InGroup;
 
+def err_atomic_op_size_zero : Error<
+  "First argument cannot be a pointer to an object of size zero">;
+
 def warn_atomic_op_oversized : Warning<
   "large atomic operation may incur "
   "significant performance penalty"
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ecd1821651140..51dcfe4cc67d9 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -40,6 +40,7 @@
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -8497,7 +8498,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 << 0 << AdjustedNumArgs << static_cast(Args.size())
 << /*is non object*/ 0 << ExprRange;
 return ExprError();
-  } else if (Args.size() > AdjustedNumArgs) {
+  }
+  if (Args.size() > AdjustedNumArgs) {
 Diag(Args[AdjustedNumArgs]->getBeginLoc(),
  diag::err_typecheck_call_too_many_args)
 << 0 << AdjustedNumArgs << static_cast(Args.size())
@@ -8544,6 +8546,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // pointer to object of size zero is not allowed
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_op_size_zero)
+<< Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..97da2582312bb 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_store(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_s

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-22 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From d1013726315209ba2517ecd767daa067b4b34143 Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] gClang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticFrontendKinds.td|  3 ++
 clang/lib/Sema/SemaChecking.cpp   | 12 ++-
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index fcffadacc8e63..0c50f125b8e05 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -328,6 +328,9 @@ def warn_atomic_op_misaligned : Warning<
   "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 
bytes)">,
   InGroup;
 
+def err_atomic_op_size_zero : Error<
+  "First argument cannot be a pointer to an object of size zero">;
+
 def warn_atomic_op_oversized : Warning<
   "large atomic operation may incur "
   "significant performance penalty"
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e33113ab9c4c1..d822fbedc9ae6 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -40,6 +40,7 @@
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -8495,7 +8496,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 << 0 << AdjustedNumArgs << static_cast(Args.size())
 << /*is non object*/ 0 << ExprRange;
 return ExprError();
-  } else if (Args.size() > AdjustedNumArgs) {
+  }
+  
+  if (Args.size() > AdjustedNumArgs) {
 Diag(Args[AdjustedNumArgs]->getBeginLoc(),
  diag::err_typecheck_call_too_many_args)
 << 0 << AdjustedNumArgs << static_cast(Args.size())
@@ -8542,6 +8545,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // pointer to object of size zero is not allowed
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_op_size_zero)
+<< Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..97da2582312bb 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_exchange(b, b, c, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acq_rel); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_acquire); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_consume); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_release); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_load(a, b, memory_order_seq_cst); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atomic_store(a, b, memory_order_relaxed); // expected-error {{First 
argument cannot be a pointer to an object of size zero}}
+  __atom

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-22 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From 9a0cb155e9d05043b31736080cb355ae73e16860 Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++-
 clang/lib/Sema/SemaChecking.cpp   | 18 ---
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..83b9f008ad9a9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8803,8 +8803,10 @@ def err_builtin_fn_use : Error<"builtin functions must 
be directly called">;
 
 def warn_call_wrong_number_of_arguments : Warning<
   "too %select{few|many}0 arguments in call to %1">;
+
 def err_atomic_builtin_must_be_pointer : Error<
-  "address argument to atomic builtin must be a pointer (%0 invalid)">;
+  "address argument to atomic builtin must be a pointer %select{|to a 
non-zero-sized object }1(%0 invalid)">;
+
 def err_atomic_builtin_must_be_pointer_intptr : Error<
   "address argument to atomic builtin must be a pointer to integer or pointer"
   " (%0 invalid)">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e33113ab9c4c1..de69fb2a68c04 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -40,6 +40,7 @@
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -3807,7 +3808,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   const PointerType *pointerType = PointerArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -3841,7 +3842,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
 Diag(DRE->getBeginLoc(), 
diag::err_atomic_builtin_must_be_pointer_intfltptr)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -8513,7 +8514,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
   const PointerType *pointerType = Ptr->getType()->getAs();
   if (!pointerType) {
 Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
-<< Ptr->getType() << Ptr->getSourceRange();
+<< Ptr->getType() << 0 << Ptr->getSourceRange();
 return ExprError();
   }
 
@@ -8542,6 +8543,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // Pointer to object of size zero is not allowed.
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
+<< Ptr->getType() << 1 << Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
@@ -8933,7 +8941,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   const PointerType *pointerType = FirstArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
@@ -8941,7 +8949,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType()) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..2024b81ce6aec 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-22 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From c6a28f1ca3fe64deee892abdf2d3646e9ccf0a87 Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++-
 clang/lib/Sema/SemaChecking.cpp   | 17 +++---
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..83b9f008ad9a9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8803,8 +8803,10 @@ def err_builtin_fn_use : Error<"builtin functions must 
be directly called">;
 
 def warn_call_wrong_number_of_arguments : Warning<
   "too %select{few|many}0 arguments in call to %1">;
+
 def err_atomic_builtin_must_be_pointer : Error<
-  "address argument to atomic builtin must be a pointer (%0 invalid)">;
+  "address argument to atomic builtin must be a pointer %select{|to a 
non-zero-sized object }1(%0 invalid)">;
+
 def err_atomic_builtin_must_be_pointer_intptr : Error<
   "address argument to atomic builtin must be a pointer to integer or pointer"
   " (%0 invalid)">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e33113ab9c4c1..3759c0c77ef97 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3807,7 +3807,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   const PointerType *pointerType = PointerArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -3841,7 +3841,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
 Diag(DRE->getBeginLoc(), 
diag::err_atomic_builtin_must_be_pointer_intfltptr)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -8513,7 +8513,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
   const PointerType *pointerType = Ptr->getType()->getAs();
   if (!pointerType) {
 Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
-<< Ptr->getType() << Ptr->getSourceRange();
+<< Ptr->getType() << 0 << Ptr->getSourceRange();
 return ExprError();
   }
 
@@ -8542,6 +8542,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // Pointer to object of size zero is not allowed.
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
+<< Ptr->getType() << 1 << Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
@@ -8933,7 +8940,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   const PointerType *pointerType = FirstArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
@@ -8941,7 +8948,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType()) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..2024b81ce6aec 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error 
{{address argument to 

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-22 Thread Hendrik Hübner via cfe-commits

HendrikHuebner wrote:

Alright, I implemented the changes you suggested. There may have been an easier 
way to modify the diagnostic though.

https://github.com/llvm/llvm-project/pull/91057
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-23 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From 487ec3df346924f71b66e5753c844c97991e Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH] [Clang] Throw error when calling atomic with pointer to zero
 size object

---
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++-
 clang/lib/Sema/SemaChecking.cpp   | 17 +++---
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6c4d92790afc5..4aab1d86fc5ec 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8808,8 +8808,10 @@ def err_builtin_fn_use : Error<"builtin functions must 
be directly called">;
 
 def warn_call_wrong_number_of_arguments : Warning<
   "too %select{few|many}0 arguments in call to %1">;
+
 def err_atomic_builtin_must_be_pointer : Error<
-  "address argument to atomic builtin must be a pointer (%0 invalid)">;
+  "address argument to atomic builtin must be a pointer %select{|to a 
non-zero-sized object }1(%0 invalid)">;
+
 def err_atomic_builtin_must_be_pointer_intptr : Error<
   "address argument to atomic builtin must be a pointer to integer or pointer"
   " (%0 invalid)">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3179d542b1f92..22ed9776f5995 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3820,7 +3820,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   const PointerType *pointerType = PointerArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -3854,7 +3854,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
 Diag(DRE->getBeginLoc(), 
diag::err_atomic_builtin_must_be_pointer_intfltptr)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -8526,7 +8526,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
   const PointerType *pointerType = Ptr->getType()->getAs();
   if (!pointerType) {
 Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
-<< Ptr->getType() << Ptr->getSourceRange();
+<< Ptr->getType() << 0 << Ptr->getSourceRange();
 return ExprError();
   }
 
@@ -8555,6 +8555,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // Pointer to object of size zero is not allowed.
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
+<< Ptr->getType() << 1 << Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
@@ -8946,7 +8953,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   const PointerType *pointerType = FirstArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
@@ -8954,7 +8961,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType()) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..2024b81ce6aec 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error 
{{address argument to 

[clang] [Clang] Throw error when calling atomic with pointer to zero size object (PR #91057)

2024-05-24 Thread Hendrik Hübner via cfe-commits

https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/91057

From 487ec3df346924f71b66e5753c844c97991e Mon Sep 17 00:00:00 2001
From: hhuebner 
Date: Sat, 4 May 2024 13:49:38 +0200
Subject: [PATCH 1/2] [Clang] Throw error when calling atomic with pointer to
 zero size object

---
 .../clang/Basic/DiagnosticSemaKinds.td|  4 ++-
 clang/lib/Sema/SemaChecking.cpp   | 17 +++---
 clang/test/Sema/atomic-ops.c  | 32 +++
 3 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6c4d92790afc5..4aab1d86fc5ec 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8808,8 +8808,10 @@ def err_builtin_fn_use : Error<"builtin functions must 
be directly called">;
 
 def warn_call_wrong_number_of_arguments : Warning<
   "too %select{few|many}0 arguments in call to %1">;
+
 def err_atomic_builtin_must_be_pointer : Error<
-  "address argument to atomic builtin must be a pointer (%0 invalid)">;
+  "address argument to atomic builtin must be a pointer %select{|to a 
non-zero-sized object }1(%0 invalid)">;
+
 def err_atomic_builtin_must_be_pointer_intptr : Error<
   "address argument to atomic builtin must be a pointer to integer or pointer"
   " (%0 invalid)">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3179d542b1f92..22ed9776f5995 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3820,7 +3820,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   const PointerType *pointerType = PointerArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -3854,7 +3854,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned 
BuiltinID, CallExpr *TheCall,
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType() && !ValType->isFloatingType()) {
 Diag(DRE->getBeginLoc(), 
diag::err_atomic_builtin_must_be_pointer_intfltptr)
-<< PointerArg->getType() << PointerArg->getSourceRange();
+<< PointerArg->getType() << 0 << PointerArg->getSourceRange();
 return true;
   }
 
@@ -8526,7 +8526,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
   const PointerType *pointerType = Ptr->getType()->getAs();
   if (!pointerType) {
 Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
-<< Ptr->getType() << Ptr->getSourceRange();
+<< Ptr->getType() << 0 << Ptr->getSourceRange();
 return ExprError();
   }
 
@@ -8555,6 +8555,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, 
SourceRange ExprRange,
 }
   }
 
+  // Pointer to object of size zero is not allowed.
+  if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
+<< Ptr->getType() << 1 << Ptr->getSourceRange();
+return ExprError();
+  }
+
   // For an arithmetic operation, the implied arithmetic must be well-formed.
   if (Form == Arithmetic) {
 // GCC does not enforce these rules for GNU atomics, but we do to help 
catch
@@ -8946,7 +8953,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   const PointerType *pointerType = FirstArg->getType()->getAs();
   if (!pointerType) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
@@ -8954,7 +8961,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult 
TheCallResult) {
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
   !ValType->isBlockPointerType()) {
 Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr)
-<< FirstArg->getType() << FirstArg->getSourceRange();
+<< FirstArg->getType() << 0 << FirstArg->getSourceRange();
 return ExprError();
   }
 
diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c
index 1d36667d6cf40..2024b81ce6aec 100644
--- a/clang/test/Sema/atomic-ops.c
+++ b/clang/test/Sema/atomic-ops.c
@@ -639,6 +639,38 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) {
   (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, -1); 
// expected-warning {{memory order argument to atomic operation is invalid}}
 }
 
+struct Z {
+  char z[];
+};
+
+void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) {
+  __atomic_exchange(b, b, c, memory_order_relaxed); // expected-error 
{{address argument