Issue |
130396
|
Summary |
non-exported variable in module interface unit has multiple addresses
|
Labels |
|
Assignees |
|
Reporter |
Diltsman
|
I posted this on Stack Overflow and it was suggested that I post this to Clang somewhere. I don't know if this is the correct place to do that.
---
I have a variable `exception_transformers` in coroutine.cpp. If this variable is in an anonymous namespace, then the output shows that `register_exception_handler()` accesses it at an address 0x18 bytes beyond where every other function accesses it. If `exception_transformers` is removed from the anonymous namespace, then it is accessed at the same address by all functions.
Is there some interaction between the C++ module and the anonymous namespace that is causing this? Is there some other cause of this problem?
---
In n4928 (C++23-ish), 9.8.2.2 [namespace.unnamed]
> ...all occurrences of *unique* in a translation unit are replaced by the
> same identifier, and this identifier differs from all other
> identifiers in the translation unit.
To me, this indicates that both anonymous namespaces behave as if they have the same name, so having the declaration and definition of `transform_exception()` in two different anonymous namespaces in the same file shouldn't be causing an issue.
---
https://godbolt.org/z/59EWe5G3b
For clang 19:
module;
#include <coroutine>
#include <expected>
#include <functional>
#include <iostream>
#include <ranges>
#include <stdexcept>
#include <system_error>
#include <type_traits>
#include <vector>
export module mycoroutine;
export import :stdexception;
export {
namespace exco {
template <typename T> using result_t = std::expected<T, std::error_code>;
}
}
namespace {
auto transform_exception() -> exco::result_t<void>;
std::vector<std::function<exco::result_t<void>()>> exception_transformers{transform_exception};
}
export {
namespace exco {
auto register_exception_handler(std::function<exco::result_t<void>()> func) {
std::cout << "register_exception_handler()" << &exception_transformers
<< ' ' << exception_transformers.size() << '\n';
exception_transformers.emplace_back(std::move(func));
std::cout << "register_exception_handler()" << &exception_transformers
<< ' ' << exception_transformers.size() << ' '
<< sizeof(exception_transformers) << '\n';
}
inline auto unerr(auto const t) {
return std::unexpected{make_error_code(t)};
}
template <typename T> struct expected_wrapper {
// Initialize as errno 0 so there are no restrictions on T
// caused by initializing this
exco::result_t<T> m_result{exco::unerr(static_cast<std::errc>(0))};
expected_wrapper<T> *&m_ptr_to_this;
expected_wrapper(expected_wrapper<T> *&ptr_to_this)
: m_ptr_to_this{ptr_to_this} {
m_ptr_to_this = this;
}
operator result_t<T>() { return std::move(m_result); };
};
} // namespace exco
namespace std {
template <typename T, typename... Args>
struct coroutine_traits<exco::result_t<T>, Args...> {
class promise_type;
template <typename T1> struct awaiter_type {
exco::result_t<T1> &m_result;
explicit awaiter_type(exco::result_t<T1> &result) noexcept
: m_result{result} {}
auto await_ready() { return m_result.has_value(); }
auto await_suspend(std::coroutine_handle<promise_type> h) {
// This should only happen when await_ready() returns false,
// which means that has_value() returned false.
h.destroy();
}
auto await_resume() {
// This should only happen when await_ready() returns true,
// which means that has_value() returned true.
return m_result.value();
}
};
class promise_type {
exco::expected_wrapper<T> *m_ptr_to_wrapper;
public:
auto initial_suspend() noexcept -> std::suspend_never { return {}; }
auto final_suspend() noexcept -> std::suspend_never { return {}; }
auto return_value(std::error_code ec) {
m_ptr_to_wrapper->m_result = std::unexpected{ec};
}
auto return_value(auto &&t) { m_ptr_to_wrapper->m_result = std::move(t); }
auto get_return_object() {
return exco::expected_wrapper<T>{m_ptr_to_wrapper};
}
auto unhandled_exception() {
for (auto &f : exception_transformers | std::views::reverse) {
try {
auto result = f();
if (!result.has_value()) {
m_ptr_to_wrapper->m_result = std::unexpected{result.error()};
return;
}
} catch (...) {
}
}
m_ptr_to_wrapper->m_result = exco::unerr(exco::stdexception::unknown);
}
template <typename T1> auto await_transform(exco::result_t<T1> value) {
m_ptr_to_wrapper->m_result = std::move(value);
return awaiter_type<T1>{m_ptr_to_wrapper->m_result};
}
};
};
} // namespace std
}
namespace {
auto transform_exception() -> exco::result_t<void> {
std::cout << "transform_exception()" << &exception_transformers << ' '
<< exception_transformers.size() << '\n';
try {
throw;
} catch (std::exception const &) {
return exco::unerr(exco::stdexception::exception);
}
}
}
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs