diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2099,6 +2099,22 @@ 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(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 --- /dev/null +++ b/clang/test/Modules/placement-new-reachable.cpp @@ -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 +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(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. +}