[Clang] Clang sometimes incorrectly makes not-exactly-matching deallocation functions cause ambiguity
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
In the following example, both MSVC and GCC doesn't think the deleted deallocation function overloads cause ambiguity and correctly call corresponding deallocation functions when an exception is thrown on initialization. But Clang thinks the deleted overloads cause ambiguity.
Per [[expr.new]/29](https://eel.is/c++draft/expr.new#29), perhaps MSVC and GCC are correct and Clang is wrong.
Link: https://godbolt.org/z/xf4qrqcME
```C++
#include
#include
#include
template
void operator delete(void*, Args&&...) = delete;
template
void operator delete[](void*, Args&&...) = delete;
struct ThrowingDefaultCtor {
struct UniqueException {};
ThrowingDefaultCtor() { throw UniqueException{}; }
};
void f() {
if (auto p = new (std::nothrow) ThrowingDefaultCtor)
delete p;
}
void g() {
if (auto p = new (std::nothrow) ThrowingDefaultCtor[2])
delete[] p;
}
void* operator new(std::size_t n, const std::nothrow_t&) noexcept { // replacing version
if (n == 0)
++n;
auto p = std::malloc(n);
std::puts("operator new(size_t, nothrow_t)");
return p;
}
void* operator new[](std::size_t n, const std::nothrow_t&) noexcept { // replacing version
if (n == 0)
++n;
auto p = std::malloc(n);
std::puts("operator new[](size_t, nothrow_t)");
return p;
}
void operator delete(void* p) noexcept { // replacing version
std::puts("operator delete(void*)");
std::free(p);
}
void operator delete(void* p, std::size_t) noexcept { // replacing version
std::puts("operator delete(void*, size_t)");
std::free(p);
}
void operator delete(void* p, const std::nothrow_t&) noexcept { // replacing version
std::puts("operator delete(void*, nothrow_t)");
std::free(p);
}
void operator delete[](void* p) noexcept { // replacing version
std::puts("operator delete[](void*)");
std::free(p);
}
void operator delete[](void* p, std::size_t) noexcept { // replacing version
std::puts("operator delete[](void*, size_t)");
std::free(p);
}
void operator delete[](void* p, const std::nothrow_t&) noexcept { // replacing version
std::puts("operator delete[](void*, nothrow_t)");
std::free(p);
}
int main() {
try {
f();
} catch(const ThrowingDefaultCtor::UniqueException&) {
}
try {
g();
} catch(const ThrowingDefaultCtor::UniqueException&) {
}
}
```
Contributor guide
Research direction
Start with the reduced example in the issue, especially functions f() and g(), and compare Clang's behavior with GCC and MSVC using the linked Godbolt case. Read the [expr.new]/29 wording and trace Clang's overload-resolution handling for deallocation after construction failure; done means the example no longer reports ambiguity and calls the corresponding deallocation functions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100