[libc] [lldb] [lld] [libcxx] [compiler-rt] [flang] [clang] [llvm] [Clang] Support MSPropertyRefExpr as placement arg to new-expression (PR #75883)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 17 15:09:31 PST 2024


https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/75883

>From 849b21f202f3c643c12f237920b137c3506996e7 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Tue, 19 Dec 2023 02:48:25 +0100
Subject: [PATCH 1/6] [Clang] Support MSPropertyRefExpr as placement arg to
 new-expression

---
 clang/include/clang/Sema/Sema.h           |  4 ++
 clang/lib/Sema/SemaExpr.cpp               | 12 ++----
 clang/lib/Sema/SemaExprCXX.cpp            |  3 ++
 clang/test/CodeGenCXX/ms-property-new.cpp | 52 +++++++++++++++++++++++
 clang/test/SemaCXX/ms-property-new.cpp    | 44 +++++++++++++++++++
 5 files changed, 107 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/ms-property-new.cpp
 create mode 100644 clang/test/SemaCXX/ms-property-new.cpp

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4ef1fe542ea54f..aeb4075374022f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2108,6 +2108,10 @@ class Sema final {
 
   bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
 
+  /// Check an argument list for placeholders that we won't try to
+  /// handle later.
+  bool CheckArgsForPlaceholders(MultiExprArg args);
+
   /// Build a function type.
   ///
   /// This routine checks the function type according to C++ rules and
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 049fdae09bb185..fcc227cf7a74f6 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5058,8 +5058,6 @@ static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS,
   return Result->isDependentType() ? Result : Ctx.DependentTy;
 }
 
-static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args);
-
 ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
                                          SourceLocation lbLoc,
                                          MultiExprArg ArgExprs,
@@ -5163,7 +5161,7 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
       return ExprError();
     ArgExprs[0] = result.get();
   } else {
-    if (checkArgsForPlaceholders(*this, ArgExprs))
+    if (CheckArgsForPlaceholders(ArgExprs))
       return ExprError();
   }
 
@@ -6912,15 +6910,13 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
   llvm_unreachable("bad builtin type kind");
 }
 
-/// Check an argument list for placeholders that we won't try to
-/// handle later.
-static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) {
+bool Sema::CheckArgsForPlaceholders(MultiExprArg args) {
   // Apply this processing to all the arguments at once instead of
   // dying at the first failure.
   bool hasInvalid = false;
   for (size_t i = 0, e = args.size(); i != e; i++) {
     if (isPlaceholderToRemoveAsArg(args[i]->getType())) {
-      ExprResult result = S.CheckPlaceholderExpr(args[i]);
+      ExprResult result = CheckPlaceholderExpr(args[i]);
       if (result.isInvalid()) hasInvalid = true;
       else args[i] = result.get();
     }
@@ -7194,7 +7190,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
   if (Result.isInvalid()) return ExprError();
   Fn = Result.get();
 
-  if (checkArgsForPlaceholders(*this, ArgExprs))
+  if (CheckArgsForPlaceholders(ArgExprs))
     return ExprError();
 
   if (getLangOpts().CPlusPlus) {
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 4ae04358d5df7c..0ca9e5b59e3c32 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2286,6 +2286,9 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
   bool PassAlignment = getLangOpts().AlignedAllocation &&
                        Alignment > NewAlignment;
 
+  if (CheckArgsForPlaceholders(PlacementArgs))
+    return ExprError();
+
   AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both;
   if (!AllocType->isDependentType() &&
       !Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
diff --git a/clang/test/CodeGenCXX/ms-property-new.cpp b/clang/test/CodeGenCXX/ms-property-new.cpp
new file mode 100644
index 00000000000000..e21ec3d6702f62
--- /dev/null
+++ b/clang/test/CodeGenCXX/ms-property-new.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s
+// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+struct S {
+  int GetX() { return 42; }
+  __declspec(property(get=GetX)) int x;
+
+  int GetY(int i, int j) { return i+j; }
+  __declspec(property(get=GetY)) int y[];
+
+  void* operator new(__SIZE_TYPE__, int);
+};
+
+template <typename T>
+struct TS {
+  T GetT() { return T(); }
+  __declspec(property(get=GetT)) T t;
+
+  T GetR(T i, T j) { return i+j; }
+  __declspec(property(get=GetR)) T r[];
+};
+
+// CHECK-LABEL: main
+int main(int argc, char **argv) {
+  S *s;
+  TS<double> *ts;
+
+  // CHECK: [[X:%.+]] = call noundef i32 @"?GetX at S@@QEAAHXZ"(ptr {{[^,]*}} %{{.+}})
+  // CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH at Z"(i64 noundef 1, i32 noundef [[X]])
+  new (s->x) S;
+
+  // CHECK: [[Y:%.+]] = call noundef i32 @"?GetY at S@@QEAAHHH at Z"(ptr {{[^,]*}} %{{.+}}, i32 noundef 1, i32 noundef 2)
+  // CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH at Z"(i64 noundef 1, i32 noundef [[Y]])
+  new ((s->y)[1][2]) S;
+
+  // CHECK: [[T:%.+]] = call noundef double @"?GetT@?$TS at N@@QEAANXZ"(ptr {{[^,]*}} %{{.+}})
+  // CHECK-NEXT: [[TI:%.+]] = fptosi double [[T]] to i32
+  // CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH at Z"(i64 noundef 1, i32 noundef [[TI]])
+  new (ts->t) S;
+
+  // CHECK: [[R:%.+]] = call noundef double @"?GetR@?$TS at N@@QEAANNN at Z"(ptr {{[^,]*}} %{{.+}}, double {{[^,]*}}, double {{[^,]*}})
+  // CHECK-NEXT: [[RI:%.+]] = fptosi double [[R]] to i32
+  // CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH at Z"(i64 noundef 1, i32 noundef [[RI]])
+  new ((ts->r)[1][2]) S;
+}
+
+#endif
\ No newline at end of file
diff --git a/clang/test/SemaCXX/ms-property-new.cpp b/clang/test/SemaCXX/ms-property-new.cpp
new file mode 100644
index 00000000000000..d17b0fdeb76715
--- /dev/null
+++ b/clang/test/SemaCXX/ms-property-new.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -ast-print -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+struct S {
+  int GetX() { return 42; }
+  __declspec(property(get=GetX)) int x;
+
+  int GetY(int i, int j) { return i+j; }
+  __declspec(property(get=GetY)) int y[];
+
+  void* operator new(__SIZE_TYPE__, int);
+};
+
+template <typename T>
+struct TS {
+  T GetT() { return T(); }
+  __declspec(property(get=GetT)) T t;
+
+  T GetR(T i, T j) { return i+j; }
+  __declspec(property(get=GetR)) T r[];
+};
+
+int main(int argc, char **argv) {
+  // CHECK: S *s;
+  // CHECK-NEXT: new (s->x) S;
+  // CHECK-NEXT: new ((s->y)[1][2]) S;
+  S *s;
+  new (s->x) S;
+  new ((s->y)[1][2]) S;
+
+  // CHECK-NEXT: TS<double> *ts;
+  // CHECK-NEXT: new (ts->t) S;
+  // CHECK-NEXT: new ((ts->r)[1][2]) S;
+  TS<double> *ts;
+  new (ts->t) S;
+  new ((ts->r)[1][2]) S;
+}
+
+#endif
\ No newline at end of file

>From f025348e9a85db6e9f5f20a4dfb28e4ce7691c80 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 4 Jan 2024 01:43:50 +0100
Subject: [PATCH 2/6] [NFC] Add newline at end of file

---
 clang/test/CodeGenCXX/ms-property-new.cpp | 2 +-
 clang/test/SemaCXX/ms-property-new.cpp    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenCXX/ms-property-new.cpp b/clang/test/CodeGenCXX/ms-property-new.cpp
index e21ec3d6702f62..bc326dda6c3776 100644
--- a/clang/test/CodeGenCXX/ms-property-new.cpp
+++ b/clang/test/CodeGenCXX/ms-property-new.cpp
@@ -49,4 +49,4 @@ int main(int argc, char **argv) {
   new ((ts->r)[1][2]) S;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/clang/test/SemaCXX/ms-property-new.cpp b/clang/test/SemaCXX/ms-property-new.cpp
index d17b0fdeb76715..9c32c3e5642629 100644
--- a/clang/test/SemaCXX/ms-property-new.cpp
+++ b/clang/test/SemaCXX/ms-property-new.cpp
@@ -41,4 +41,4 @@ int main(int argc, char **argv) {
   new ((ts->r)[1][2]) S;
 }
 
-#endif
\ No newline at end of file
+#endif

>From 9b540dad6b5beebe6fd8b6b7270c6fc48c42490a Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 4 Jan 2024 05:07:21 +0100
Subject: [PATCH 3/6] [Clang] Add tests for placeholder exprs in placement-args
 of new-expression

---
 .../CodeGenCXX/placement-new-ms-__noop.cpp    | 12 ++++
 .../CodeGenObjCXX/property-placement-new.mm   | 46 +++++++++++++
 clang/test/SemaCXX/builtin-std-move.cpp       | 41 +++++++++++
 .../placement-new-bound-member-function.cpp   | 68 +++++++++++++++++++
 clang/test/SemaCXX/placement-new-builtin.cpp  | 11 +++
 clang/test/SemaCXX/placement-new-matrix.cpp   | 26 +++++++
 .../test/SemaCXX/placement-new-ms-__noop.cpp  | 12 ++++
 .../test/SemaObjCXX/property-placement-new.mm | 28 ++++++++
 8 files changed, 244 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/placement-new-ms-__noop.cpp
 create mode 100644 clang/test/CodeGenObjCXX/property-placement-new.mm
 create mode 100644 clang/test/SemaCXX/placement-new-bound-member-function.cpp
 create mode 100644 clang/test/SemaCXX/placement-new-builtin.cpp
 create mode 100644 clang/test/SemaCXX/placement-new-matrix.cpp
 create mode 100644 clang/test/SemaCXX/placement-new-ms-__noop.cpp
 create mode 100644 clang/test/SemaObjCXX/property-placement-new.mm

diff --git a/clang/test/CodeGenCXX/placement-new-ms-__noop.cpp b/clang/test/CodeGenCXX/placement-new-ms-__noop.cpp
new file mode 100644
index 00000000000000..96149fdff98b45
--- /dev/null
+++ b/clang/test/CodeGenCXX/placement-new-ms-__noop.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+struct S {
+  void* operator new(__SIZE_TYPE__, int);
+};
+
+int main() {
+  // CHECK: call {{.*}} ptr @"??2S@@SAPEAX_KH at Z"(i64 {{.*}} 1, i32 {{.*}} 0)
+  // CHECK: call {{.*}} ptr @"??2S@@SAPEAX_KH at Z"(i64 {{.*}} 1, i32 {{.*}} 0)
+  new (__noop) S;
+  new ((__noop)) S;
+}
diff --git a/clang/test/CodeGenObjCXX/property-placement-new.mm b/clang/test/CodeGenObjCXX/property-placement-new.mm
new file mode 100644
index 00000000000000..3f4a3a94b72537
--- /dev/null
+++ b/clang/test/CodeGenObjCXX/property-placement-new.mm
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -x objective-c++ -std=c++11 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: [[NAME:@.*]] = private unnamed_addr constant [9 x i8] c"position\00"
+// CHECK: [[SEL:@.*]] = internal externally_initialized global ptr [[NAME]]
+
+ at interface I {
+  int position;
+}
+ at property(nonatomic) int position;
+ at end
+
+struct S {
+  void *operator new(__SIZE_TYPE__, int);
+};
+
+template <typename T>
+struct TS {
+  void *operator new(__SIZE_TYPE__, T);
+};
+
+I *GetI();
+
+int main() {
+  @autoreleasepool {
+    // CHECK: [[I:%.+]] = alloca ptr
+    auto* i = GetI();
+    i.position = 42;
+
+    // This is so we can find the next line more easily.
+    // CHECK: store double
+    double d = 42.0;
+
+    // CHECK: [[I1:%.+]] = load ptr, ptr [[I]]
+    // CHECK-NEXT: [[SEL1:%.+]] = load ptr, ptr [[SEL]]
+    // CHECK-NEXT: [[POS1:%.+]] = call {{.*}} i32 @objc_msgSend(ptr {{.*}} [[I1]], ptr {{.*}} [[SEL1]])
+    // CHECK-NEXT: call {{.*}} ptr @_ZN1SnwEmi(i64 {{.*}} 1, i32 {{.*}} [[POS1]])
+    new (i.position) S;
+
+    // CHECK: [[I2:%.+]] = load ptr, ptr [[I]]
+    // CHECK-NEXT: [[SEL2:%.+]] = load ptr, ptr [[SEL]]
+    // CHECK-NEXT: [[POS2:%.+]] = call {{.*}} i32 @objc_msgSend(ptr {{.*}} [[I2]], ptr {{.*}} [[SEL2]])
+    // CHECK-NEXT: [[DBL:%.+]] = sitofp i32 [[POS2]] to double
+    // CHECK-NEXT: call {{.*}} ptr  @_ZN2TSIdEnwEmd(i64 {{.*}} 1, double {{.*}} [[DBL]])
+    new (i.position) TS<double>;
+  }
+}
diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index adad66afc2cbd9..acece1049ca53c 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -12,6 +12,7 @@ namespace std {
   template<typename T> CONSTEXPR T &&move(T &x) {
     static_assert(T::moveable, "instantiated move"); // expected-error {{no member named 'moveable' in 'B'}}
                                                      // expected-error at -1 {{no member named 'moveable' in 'C'}}
+                                                     // expected-error at -2 {{no member named 'moveable' in 'D'}}
     return static_cast<T&&>(x);
   }
 
@@ -23,6 +24,7 @@ namespace std {
 
   template<typename T> CONSTEXPR auto move_if_noexcept(T &x) -> typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type {
     static_assert(T::moveable, "instantiated move_if_noexcept"); // expected-error {{no member named 'moveable' in 'B'}}
+                                                                 // expected-error at -1 {{no member named 'moveable' in 'D'}}
     return static_cast<typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type>(x);
   }
 
@@ -36,6 +38,7 @@ namespace std {
   template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &x) {
     static_assert(T::moveable, "instantiated forward"); // expected-error {{no member named 'moveable' in 'B'}}
                                                         // expected-error at -1 {{no member named 'moveable' in 'C'}}
+                                                        // expected-error at -2 {{no member named 'moveable' in 'D'}}
     return static_cast<T&&>(x);
   }
   template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &&x) {
@@ -67,21 +70,25 @@ namespace std {
   CONSTEXPR auto forward_like(T &&t) -> ForwardLikeRetType<U, T> {
     using TT = typename remove_reference<T>::type;
     static_assert(TT::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
+                                                          // expected-error at -1 {{no member named 'moveable' in 'D'}}
     return static_cast<ForwardLikeRetType<U, T>>(t);
   }
 
   template<typename T> CONSTEXPR const T &as_const(T &x) {
     static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
+                                                         // expected-error at -1 {{no member named 'moveable' in 'D'}}
     return x;
   }
 
   template<typename T> CONSTEXPR T *addressof(T &x) {
     static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
+                                                          // expected-error at -1 {{no member named 'moveable' in 'D'}}
     return __builtin_addressof(x);
   }
 
   template<typename T> CONSTEXPR T *__addressof(T &x) {
     static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
+                                                            // expected-error at -1 {{no member named 'moveable' in 'D'}}
     return __builtin_addressof(x);
   }
 }
@@ -163,6 +170,40 @@ void attribute_const() {
   std::as_const(n); // expected-warning {{ignoring return value}}
 }
 
+struct D {
+  void* operator new(__SIZE_TYPE__, D&&(*)(D&));
+  void* operator new(__SIZE_TYPE__, D*(*)(D&));
+  void* operator new(__SIZE_TYPE__, const D&(*)(D&));
+};
+
+#if __cplusplus <= 201703L
+// expected-warning@#10 {{non-addressable}}
+// expected-warning@#11 {{non-addressable}}
+// expected-warning@#12 {{non-addressable}}
+// expected-warning@#13 {{non-addressable}}
+// expected-warning@#14 {{non-addressable}}
+// expected-warning@#15 {{non-addressable}}
+// expected-warning@#16 {{non-addressable}}
+#else
+// expected-error@#10 {{non-addressable}}
+// expected-error@#11 {{non-addressable}}
+// expected-error@#12 {{non-addressable}}
+// expected-error@#13 {{non-addressable}}
+// expected-error@#14 {{non-addressable}}
+// expected-error@#15 {{non-addressable}}
+// expected-error@#16 {{non-addressable}}
+#endif
+
+void placement_new() {
+  new (std::move<D>) D; // #10 expected-note {{instantiation of}}
+  new (std::move_if_noexcept<D>) D; // #11 expected-note {{instantiation of}}
+  new (std::forward<D>) D; // #12 expected-note {{instantiation of}}
+  new (std::forward_like<D>) D; // #13 expected-note {{instantiation of}}
+  new (std::addressof<D>) D; // #14 expected-note {{instantiation of}}
+  new (std::__addressof<D>) D; // #15 expected-note {{instantiation of}}
+  new (std::as_const<D>) D; // #16 expected-note {{instantiation of}}
+}
+
 namespace std {
   template<typename T> int &move(T);
 }
diff --git a/clang/test/SemaCXX/placement-new-bound-member-function.cpp b/clang/test/SemaCXX/placement-new-bound-member-function.cpp
new file mode 100644
index 00000000000000..57338942533254
--- /dev/null
+++ b/clang/test/SemaCXX/placement-new-bound-member-function.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+struct S {
+  int NoArgs();
+  int OneArg(int);
+
+  template <typename T>
+  T TemplNoArgs(); // expected-note {{possible target for call}} // expected-note {{possible target for call}}
+
+  template <typename T>
+  T TemplOneArg(T); // expected-note {{possible target for call}} // expected-note {{possible target for call}}
+
+  void* operator new(__SIZE_TYPE__, int);
+};
+
+S* GetS();
+
+int test() {
+  S s, *ps = GetS();
+  int (S::*pNoArgs)() = &S::NoArgs;
+  int (S::*pOneArg)(int) = &S::OneArg;
+  int (S::*pTemplNoArgs)() = &S::TemplNoArgs<int>;
+  int (S::*pTemplOneArg)(int) = &S::TemplOneArg<int>;
+
+  new (s.NoArgs()) S;
+  new (s.OneArg(1)) S;
+  new (ps->NoArgs()) S;
+  new (ps->OneArg(1)) S;
+  new ((s.*pNoArgs)()) S;
+  new ((s.*pOneArg)(1)) S;
+  new ((ps->*pNoArgs)()) S;
+  new ((ps->*pOneArg)(1)) S;
+
+  new (s.TemplNoArgs<int>()) S;
+  new (s.TemplOneArg<int>(1)) S;
+  new (ps->TemplNoArgs<int>()) S;
+  new (ps->TemplOneArg<int>(1)) S;
+  new ((s.*pTemplNoArgs)()) S;
+  new ((s.*pTemplOneArg)(1)) S;
+  new ((ps->*pTemplNoArgs)()) S;
+  new ((ps->*pTemplOneArg)(1)) S;
+
+  new (s.NoArgs) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (s.OneArg) S; // expected-error {{reference to non-static member function must be called}}
+  new (ps->NoArgs) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (ps->OneArg) S; // expected-error {{reference to non-static member function must be called}}
+  new (s.*pNoArgs) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (s.*pOneArg) S; // expected-error {{reference to non-static member function must be called}}
+  new (ps->*pNoArgs) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (ps->*pOneArg) S; // expected-error {{reference to non-static member function must be called}}
+  new ((s.*pNoArgs)) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new ((s.*pOneArg)) S; // expected-error {{reference to non-static member function must be called}}
+  new ((ps->*pNoArgs)) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new ((ps->*pOneArg)) S; // expected-error {{reference to non-static member function must be called}}
+
+  new (s.TemplNoArgs<int>) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (s.TemplOneArg<int>) S; // expected-error {{reference to non-static member function must be called}}
+  new (ps->TemplNoArgs<int>) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (ps->TemplOneArg<int>) S; // expected-error {{reference to non-static member function must be called}}
+  new (s.*pTemplNoArgs) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (s.*pTemplOneArg) S; // expected-error {{reference to non-static member function must be called}}
+  new (ps->*pTemplNoArgs) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new (ps->*pTemplOneArg) S; // expected-error {{reference to non-static member function must be called}}
+  new ((s.*pTemplNoArgs)) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new ((s.*pTemplOneArg)) S; // expected-error {{reference to non-static member function must be called}}
+  new ((ps->*pTemplNoArgs)) S; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+  new ((ps->*pTemplOneArg)) S; // expected-error {{reference to non-static member function must be called}}
+}
diff --git a/clang/test/SemaCXX/placement-new-builtin.cpp b/clang/test/SemaCXX/placement-new-builtin.cpp
new file mode 100644
index 00000000000000..5776a94dc3ad81
--- /dev/null
+++ b/clang/test/SemaCXX/placement-new-builtin.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+struct S {
+  void* operator new(__SIZE_TYPE__, char*);
+  void* operator new(__SIZE_TYPE__, __SIZE_TYPE__);
+};
+
+int main() {
+  new (__builtin_strchr) S; // expected-error {{builtin functions must be directly called}}
+  new ((__builtin_strlen)) S; // expected-error {{builtin functions must be directly called}}
+}
diff --git a/clang/test/SemaCXX/placement-new-matrix.cpp b/clang/test/SemaCXX/placement-new-matrix.cpp
new file mode 100644
index 00000000000000..7168e60bdbb007
--- /dev/null
+++ b/clang/test/SemaCXX/placement-new-matrix.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fenable-matrix -fsyntax-only -verify %s -std=c++11
+
+using Matrix = int __attribute__((matrix_type(4, 3)));
+
+template <__SIZE_TYPE__ a, __SIZE_TYPE__ b>
+using TMatrix = int __attribute__((matrix_type(a, b)));
+
+struct S {
+    void* operator new(__SIZE_TYPE__, int);
+    void* operator new(__SIZE_TYPE__, Matrix);
+    void* operator new(__SIZE_TYPE__, TMatrix<2, 2>);
+};
+
+int main() {
+    Matrix m;
+    TMatrix<2, 2> tm;
+
+    new (m) S {};
+    new (tm) S {};
+
+    new (m[1][1]) S {};
+    new (tm[1][1]) S {};
+
+    new (m[1]) S {}; // expected-error {{single subscript expressions are not allowed for matrix values}}
+    new (tm[1]) S {}; // expected-error {{single subscript expressions are not allowed for matrix values}}
+}
diff --git a/clang/test/SemaCXX/placement-new-ms-__noop.cpp b/clang/test/SemaCXX/placement-new-ms-__noop.cpp
new file mode 100644
index 00000000000000..a251676c000126
--- /dev/null
+++ b/clang/test/SemaCXX/placement-new-ms-__noop.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify %s -std=c++11
+// expected-no-diagnostics
+
+struct S {
+  void* operator new(__SIZE_TYPE__, int);
+};
+
+int main() {
+  // MSVC supports __noop with no arguments or (), so we do as well.
+  new (__noop) S;
+  new ((__noop)) S;
+}
diff --git a/clang/test/SemaObjCXX/property-placement-new.mm b/clang/test/SemaObjCXX/property-placement-new.mm
new file mode 100644
index 00000000000000..30d02428a4c33d
--- /dev/null
+++ b/clang/test/SemaObjCXX/property-placement-new.mm
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
+
+ at interface I {
+  int position;
+}
+ at property(nonatomic) int position;
+ at end
+
+struct S {
+  void *operator new(__SIZE_TYPE__, int);
+};
+
+template <typename T>
+struct TS {
+  void *operator new(__SIZE_TYPE__, T);
+};
+
+I *GetI();
+
+int main() {
+  @autoreleasepool {
+    auto* i = GetI();
+    i.position = 42;
+    new (i.position) S;
+    new (i.position) TS<double>;
+  }
+}

>From 56c8413ef07adb8baa95fc7e13058731ee0beb35 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 4 Jan 2024 19:12:11 +0100
Subject: [PATCH 4/6] [Clang] [NFC] Modernise expected directives

---
 clang/test/SemaCXX/builtin-std-move.cpp | 76 ++++++++++++-------------
 1 file changed, 35 insertions(+), 41 deletions(-)

diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index acece1049ca53c..3911c066ebcec5 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++17 -verify %s
-// RUN: %clang_cc1 -std=c++17 -verify %s -DNO_CONSTEXPR
-// RUN: %clang_cc1 -std=c++20 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s
+// RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -DNO_CONSTEXPR
+// RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s
 
 namespace std {
 #ifndef NO_CONSTEXPR
@@ -137,27 +137,24 @@ C &&(&rMove)(C&) = std::move; // #8 expected-note {{instantiation of}}
 C &&(&rForward)(C&) = std::forward<C>; // #9 expected-note {{instantiation of}}
 int (&rUnrelatedMove)(B, B) = std::move;
 
-#if __cplusplus <= 201703L
-// expected-warning@#1 {{non-addressable}}
-// expected-warning@#2 {{non-addressable}}
-// expected-warning@#3 {{non-addressable}}
-// expected-warning@#4 {{non-addressable}}
-// expected-warning@#5 {{non-addressable}}
-// expected-warning@#6 {{non-addressable}}
-// expected-warning@#7 {{non-addressable}}
-// expected-warning@#8 {{non-addressable}}
-// expected-warning@#9 {{non-addressable}}
-#else
-// expected-error@#1 {{non-addressable}}
-// expected-error@#2 {{non-addressable}}
-// expected-error@#3 {{non-addressable}}
-// expected-error@#4 {{non-addressable}}
-// expected-error@#5 {{non-addressable}}
-// expected-error@#6 {{non-addressable}}
-// expected-error@#7 {{non-addressable}}
-// expected-error@#8 {{non-addressable}}
-// expected-error@#9 {{non-addressable}}
-#endif
+// cxx17-warning@#1 {{non-addressable}}
+// cxx17-warning@#2 {{non-addressable}}
+// cxx17-warning@#3 {{non-addressable}}
+// cxx17-warning@#4 {{non-addressable}}
+// cxx17-warning@#5 {{non-addressable}}
+// cxx17-warning@#6 {{non-addressable}}
+// cxx17-warning@#7 {{non-addressable}}
+// cxx17-warning@#8 {{non-addressable}}
+// cxx17-warning@#9 {{non-addressable}}
+// cxx20-error@#1 {{non-addressable}}
+// cxx20-error@#2 {{non-addressable}}
+// cxx20-error@#3 {{non-addressable}}
+// cxx20-error@#4 {{non-addressable}}
+// cxx20-error@#5 {{non-addressable}}
+// cxx20-error@#6 {{non-addressable}}
+// cxx20-error@#7 {{non-addressable}}
+// cxx20-error@#8 {{non-addressable}}
+// cxx20-error@#9 {{non-addressable}}
 
 void attribute_const() {
   int n;
@@ -176,23 +173,20 @@ struct D {
   void* operator new(__SIZE_TYPE__, const D&(*)(D&));
 };
 
-#if __cplusplus <= 201703L
-// expected-warning@#10 {{non-addressable}}
-// expected-warning@#11 {{non-addressable}}
-// expected-warning@#12 {{non-addressable}}
-// expected-warning@#13 {{non-addressable}}
-// expected-warning@#14 {{non-addressable}}
-// expected-warning@#15 {{non-addressable}}
-// expected-warning@#16 {{non-addressable}}
-#else
-// expected-error@#10 {{non-addressable}}
-// expected-error@#11 {{non-addressable}}
-// expected-error@#12 {{non-addressable}}
-// expected-error@#13 {{non-addressable}}
-// expected-error@#14 {{non-addressable}}
-// expected-error@#15 {{non-addressable}}
-// expected-error@#16 {{non-addressable}}
-#endif
+// cxx17-warning@#10 {{non-addressable}}
+// cxx17-warning@#11 {{non-addressable}}
+// cxx17-warning@#12 {{non-addressable}}
+// cxx17-warning@#13 {{non-addressable}}
+// cxx17-warning@#14 {{non-addressable}}
+// cxx17-warning@#15 {{non-addressable}}
+// cxx17-warning@#16 {{non-addressable}}
+// cxx20-error@#10 {{non-addressable}}
+// cxx20-error@#11 {{non-addressable}}
+// cxx20-error@#12 {{non-addressable}}
+// cxx20-error@#13 {{non-addressable}}
+// cxx20-error@#14 {{non-addressable}}
+// cxx20-error@#15 {{non-addressable}}
+// cxx20-error@#16 {{non-addressable}}
 
 void placement_new() {
   new (std::move<D>) D; // #10 expected-note {{instantiation of}}

>From 742f4c30cd61e53a0e10acf318173f309d2c7d44 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 4 Jan 2024 19:43:59 +0100
Subject: [PATCH 5/6] [Clang] [NFC] Reorder expected directives

---
 clang/test/SemaCXX/builtin-std-move.cpp | 66 ++++++-------------------
 1 file changed, 16 insertions(+), 50 deletions(-)

diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index 3911c066ebcec5..e20bf8e156e193 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -123,39 +123,20 @@ A &forward_rval_as_lval() {
 }
 
 struct B {};
-B &&(*pMove)(B&) = std::move; // #1 expected-note {{instantiation of}}
-B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // #2 expected-note {{instantiation of}}
-B &&(*pForward)(B&) = &std::forward<B>; // #3 expected-note {{instantiation of}}
-B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // #4 expected-note {{instantiation of}}
-const B &(*pAsConst)(B&) = &std::as_const; // #5 expected-note {{instantiation of}}
-B *(*pAddressof)(B&) = &std::addressof; // #6 expected-note {{instantiation of}}
-B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #7 expected-note {{instantiation of}}
+B &&(*pMove)(B&) = std::move;                            // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept;     // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+B &&(*pForward)(B&) = &std::forward<B>;                  // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+const B &(*pAsConst)(B&) = &std::as_const;               // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+B *(*pAddressof)(B&) = &std::addressof;                  // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+B *(*pUnderUnderAddressof)(B&) = &std::__addressof;      // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
 int (*pUnrelatedMove)(B, B) = std::move;
 
 struct C {};
-C &&(&rMove)(C&) = std::move; // #8 expected-note {{instantiation of}}
-C &&(&rForward)(C&) = std::forward<C>; // #9 expected-note {{instantiation of}}
+C &&(&rMove)(C&) = std::move;          // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+C &&(&rForward)(C&) = std::forward<C>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
 int (&rUnrelatedMove)(B, B) = std::move;
 
-// cxx17-warning@#1 {{non-addressable}}
-// cxx17-warning@#2 {{non-addressable}}
-// cxx17-warning@#3 {{non-addressable}}
-// cxx17-warning@#4 {{non-addressable}}
-// cxx17-warning@#5 {{non-addressable}}
-// cxx17-warning@#6 {{non-addressable}}
-// cxx17-warning@#7 {{non-addressable}}
-// cxx17-warning@#8 {{non-addressable}}
-// cxx17-warning@#9 {{non-addressable}}
-// cxx20-error@#1 {{non-addressable}}
-// cxx20-error@#2 {{non-addressable}}
-// cxx20-error@#3 {{non-addressable}}
-// cxx20-error@#4 {{non-addressable}}
-// cxx20-error@#5 {{non-addressable}}
-// cxx20-error@#6 {{non-addressable}}
-// cxx20-error@#7 {{non-addressable}}
-// cxx20-error@#8 {{non-addressable}}
-// cxx20-error@#9 {{non-addressable}}
-
 void attribute_const() {
   int n;
   std::move(n); // expected-warning {{ignoring return value}}
@@ -173,29 +154,14 @@ struct D {
   void* operator new(__SIZE_TYPE__, const D&(*)(D&));
 };
 
-// cxx17-warning@#10 {{non-addressable}}
-// cxx17-warning@#11 {{non-addressable}}
-// cxx17-warning@#12 {{non-addressable}}
-// cxx17-warning@#13 {{non-addressable}}
-// cxx17-warning@#14 {{non-addressable}}
-// cxx17-warning@#15 {{non-addressable}}
-// cxx17-warning@#16 {{non-addressable}}
-// cxx20-error@#10 {{non-addressable}}
-// cxx20-error@#11 {{non-addressable}}
-// cxx20-error@#12 {{non-addressable}}
-// cxx20-error@#13 {{non-addressable}}
-// cxx20-error@#14 {{non-addressable}}
-// cxx20-error@#15 {{non-addressable}}
-// cxx20-error@#16 {{non-addressable}}
-
 void placement_new() {
-  new (std::move<D>) D; // #10 expected-note {{instantiation of}}
-  new (std::move_if_noexcept<D>) D; // #11 expected-note {{instantiation of}}
-  new (std::forward<D>) D; // #12 expected-note {{instantiation of}}
-  new (std::forward_like<D>) D; // #13 expected-note {{instantiation of}}
-  new (std::addressof<D>) D; // #14 expected-note {{instantiation of}}
-  new (std::__addressof<D>) D; // #15 expected-note {{instantiation of}}
-  new (std::as_const<D>) D; // #16 expected-note {{instantiation of}}
+  new (std::move<D>) D;             // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+  new (std::move_if_noexcept<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+  new (std::forward<D>) D;          // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+  new (std::forward_like<D>) D;     // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+  new (std::addressof<D>) D;        // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+  new (std::__addressof<D>) D;      // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
+  new (std::as_const<D>) D;         // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
 }
 
 namespace std {

>From 0ab962271e3499550e396ee66af85a919efdd3ea Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 4 Jan 2024 19:50:24 +0100
Subject: [PATCH 6/6] [Clang] [NFC] Update release notes

---
 clang/docs/ReleaseNotes.rst | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e45e016b3d66bd..2020befb1f0852 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -569,6 +569,30 @@ Improvements to Clang's diagnostics
   and template friend declarations with a constraint that depends on a template parameter from an
   enclosing template must be a definition.
 
+- Clang now emits more descriptive diagnostics for 'unusual' expressions (e.g. incomplete index
+  expressions on matrix types or builtin functions without an argument list) as placement-args
+  to new-expressions.
+
+  Before:
+
+  .. code-block:: text
+
+    error: no matching function for call to 'operator new'
+       13 |     new (__builtin_memset) S {};
+          |     ^   ~~~~~~~~~~~~~~~~~~
+
+    note: candidate function not viable: no known conversion from '<builtin fn type>' to 'int' for 2nd argument
+        5 |     void* operator new(__SIZE_TYPE__, int);
+          |           ^
+
+  After:
+
+  .. code-block:: text
+
+    error: builtin functions must be directly called
+       13 |     new (__builtin_memset) S {};
+          |          ^
+
 
 Improvements to Clang's time-trace
 ----------------------------------
@@ -765,6 +789,12 @@ Bug Fixes in This Version
   Fixes (`#77583 <https://github.com/llvm/llvm-project/issues/77583>`_)
 - Fix an issue where CTAD fails for function-type/array-type arguments.
   Fixes (`#51710 <https://github.com/llvm/llvm-project/issues/51710>`_)
+- The MS ``__noop`` builtin without an argument list is now accepted
+  in the placement-args of new-expressions, matching MSVC's behaviour.
+- Fix an issue that caused MS ``__decspec(property)`` accesses as well as
+  Objective-C++ property accesses to not be converted to a function call
+  to the getter in the placement-args of new-expressions.
+  Fixes (`#65053 <https://github.com/llvm/llvm-project/issues/65053>`_)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



More information about the cfe-commits mailing list