[C++20] [Modules] Make placement allocation functions always visible
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>
Mon, 9 Jan 2023 02:39:35 +0000 (10:39 +0800)
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>
Mon, 9 Jan 2023 02:40:23 +0000 (10:40 +0800)
Close https://github.com/llvm/llvm-project/issues/59601.

This is actually a workaround for the issue. See the comments and the
test for example. The proper fix should make the placement allocation
functions acceptable based on the context. But it is harder and more
complex on the one side. On the other side, such workaround won't be too
bad in practice since users rarely call the placement allocation
functions directly.

So personally I prefer to address such problems in the simpler way.

Reviewed By: royjacobson

Differential Revision: https://reviews.llvm.org/D141023

clang/lib/Sema/SemaLookup.cpp
clang/test/Modules/placement-new-reachable.cpp [new file with mode: 0644]

index 97b3c97..4ec8a37 100644 (file)
@@ -2099,6 +2099,22 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) {
   if (auto *DeductionGuide = ND->getDeclName().getCXXDeductionGuideTemplate())
     return SemaRef.hasReachableDefinition(DeductionGuide);
 
+  // FIXME: The lookup for allocation function is a standalone process.
+  // (We can find the logics in Sema::FindAllocationFunctions)
+  //
+  // Such structure makes it a problem when we instantiate a template
+  // declaration using placement allocation function if the placement
+  // allocation function is invisible.
+  // (See https://github.com/llvm/llvm-project/issues/59601)
+  //
+  // Here we workaround it by making the placement allocation functions
+  // always acceptable. The downside is that we can't diagnose the direct
+  // use of the invisible placement allocation functions. (Although such uses
+  // should be rare).
+  if (auto *FD = dyn_cast<FunctionDecl>(ND);
+      FD && FD->isReservedGlobalPlacementOperator())
+    return true;
+
   auto *DC = ND->getDeclContext();
   // If ND is not visible and it is at namespace scope, it shouldn't be found
   // by name lookup.
diff --git a/clang/test/Modules/placement-new-reachable.cpp b/clang/test/Modules/placement-new-reachable.cpp
new file mode 100644 (file)
index 0000000..2926317
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -o %t/A.pcm
+// RUN: %clang_cc1 -std=c++20 %t/Use.cpp -fprebuilt-module-path=%t -fsyntax-only -verify
+
+//--- placement.h
+namespace std {
+  using size_t = decltype(sizeof(0));
+}
+void *operator new(std::size_t, void *p) { return p; }
+
+//--- A.cppm
+module;
+#include "placement.h"
+export module A;
+export template<class T>
+struct A {
+    A(void *p) : ptr(new (p) T(43)) {}
+private:
+    void *ptr;
+};
+
+export struct B {
+    B(void *p) : ptr(new (p) int(43)) {}
+private:
+    void *ptr;
+};
+
+//--- Use.cpp
+// expected-no-diagnostics
+import A;
+void bar(int *);
+void foo(void *ptr) {
+    A<int>(nullptr); // Good. It should be OK to construct A.
+    void *p = ::operator new(sizeof(int), ptr); // Bad. The function shouldn't be visible here.
+    void *q = new (ptr) int(43); // Good. We don't call the placement allocation function directly.
+}