| Issue |
55406
|
| Summary |
-Wthread-safety coroutine ICE
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
urnathan
|
this use of a stmt-_expression_ inside a co_return causes an ICE
```
Task Foo() {
co_return ({ static int frame = 0; 0; });
}
```
On today's trunk:
```
zathras:18>build/bin/clang++ -c -std=c++17 -fcoroutines-ts -Wthread-safety coro-thread-ice.cc
clang++: /home/nathan/llvm/trunk/clang/lib/Analysis/ThreadSafety.cpp:530: (anonymous namespace)::LocalVariableMap::Context (anonymous namespace)::LocalVariableMap::addDefinition(const clang::NamedDecl *, const clang::Expr *, (anonymous namespace)::LocalVariableMap::Context): Assertion `!Ctx.contains(D)' failed.
...
#11 0x000000000bef2835 (anonymous namespace)::LocalVariableMap::addDefinition(clang::NamedDecl const*, clang::Expr const*, llvm::ImmutableMap<clang::NamedDecl const*, unsigned int, llvm::ImutKeyValueInfo<clang::NamedDecl const*, unsigned int>>) /data/users/nathans/llvm/trunk/clang/lib/Analysis/ThreadSafety.cpp:0:5
#12 0x000000000beefd18 (anonymous namespace)::VarMapBuilder::VisitDeclStmt(clang::DeclStmt const*) /data/users/nathans/llvm/trunk/clang/lib/Analysis/ThreadSafety.cpp:618:21
#13 0x000000000beeddb9 clang::StmtVisitorBase<llvm::make_const_ptr, (anonymous namespace)::VarMapBuilder, void>::Visit(clang::Stmt const*) /data/users/nathans/llvm/trunk/build/tools/clang/include/clang/AST/StmtNodes.inc:97:1
#14 0x000000000bee7549 (anonymous namespace)::LocalVariableMap::traverseCFG(clang::CFG*, clang::PostOrderCFGView const*, std::vector<(anonymous namespace)::CFGBlockInfo, std::allocator<(anonymous namespace)::CFGBlockInfo>>&) /data/users/nathans/llvm/trunk/clang/lib/Analysis/ThreadSafety.cpp:780:11
#15 0x000000000bee4fb2 (anonymous namespace)::ThreadSafetyAnalyzer::runAnalysis(clang::AnalysisDeclContext&) /data/users/nathans/llvm/trunk/clang/lib/Analysis/ThreadSafety.cpp:2252:15
#16 0x000000000bee4d23 clang::threadSafety::runThreadSafetyAnalysis(clang::AnalysisDeclContext&, clang::threadSafety::ThreadSafetyHandler&, clang::threadSafety::BeforeSet**) /data/users/nathans/llvm/trunk/clang/lib/Analysis/ThreadSafety.cpp:2466:1
#17 0x000000000aba3948 clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::QualType) /data/users/nathans/llvm/trunk/clang/lib/Sema/AnalysisBasedWarnings.cpp:2360:14
```
Here's the full reproducer:
```
// -cc1 -triple x86_64 -Wthread-safety -std=c++17 -fcoroutines-ts
// ICE: clang/lib/Analysis/ThreadSafety.cpp:530: (anonymous namespace)::LocalVariableMap::Context (anonymous namespace)::LocalVariableMap::addDefinition(const clang::NamedDecl *, const clang::Expr *, (anonymous namespace)::LocalVariableMap::Context): Assertion `!Ctx.contains(D)' failed.
#if USE_HEADER
#include <coroutine>
#else
namespace std
{
typedef long unsigned int size_t;
typedef decltype(nullptr) nullptr_t;
template<typename...> using __void_t = void;
inline namespace __n4861 {
template <typename _Result, typename = void>
struct __coroutine_traits_impl {};
template <typename _Result>
struct __coroutine_traits_impl<_Result,
__void_t<typename _Result::promise_type>>
{
using promise_type = typename _Result::promise_type;
};
template <typename _Result, typename...>
struct coroutine_traits : __coroutine_traits_impl<_Result> {};
template <typename _Promise = void>
struct coroutine_handle;
template <> struct
coroutine_handle<void>
{
public:
constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {}
constexpr coroutine_handle(std::nullptr_t __h) noexcept
: _M_fr_ptr(__h)
{}
coroutine_handle& operator=(std::nullptr_t) noexcept
{
_M_fr_ptr = nullptr;
return *this;
}
public:
constexpr void* address() const noexcept { return _M_fr_ptr; }
constexpr static coroutine_handle from_address(void* __a) noexcept
{
coroutine_handle __self;
__self._M_fr_ptr = __a;
return __self;
}
public:
constexpr explicit operator bool() const noexcept
{
return bool(_M_fr_ptr);
}
bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); }
void operator()() const { resume(); }
void resume() const { __builtin_coro_resume(_M_fr_ptr); }
void destroy() const { __builtin_coro_destroy(_M_fr_ptr); }
protected:
void* _M_fr_ptr;
};
template <typename _Promise>
struct coroutine_handle : coroutine_handle<>
{
using coroutine_handle<>::coroutine_handle;
static coroutine_handle from_promise(_Promise& p)
{
coroutine_handle __self;
__self._M_fr_ptr
= __builtin_coro_promise((char*) &p, __alignof(_Promise), true);
return __self;
}
coroutine_handle& operator=(std::nullptr_t) noexcept
{
coroutine_handle<>::operator=(nullptr);
return *this;
}
constexpr static coroutine_handle from_address(void* __a) noexcept
{
coroutine_handle __self;
__self._M_fr_ptr = __a;
return __self;
}
_Promise& promise() const
{
void* __t
= __builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false);
return *static_cast<_Promise*>(__t);
}
};
struct noop_coroutine_promise
{
};
void __dummy_resume_destroy() __attribute__((__weak__));
void __dummy_resume_destroy() {}
struct __noop_coro_frame
{
void (*__r)() = __dummy_resume_destroy;
void (*__d)() = __dummy_resume_destroy;
struct noop_coroutine_promise __p;
} __noop_coro_fr __attribute__((__weak__));
template <>
struct coroutine_handle<noop_coroutine_promise> : public coroutine_handle<>
{
using _Promise = noop_coroutine_promise;
public:
constexpr explicit operator bool() const noexcept { return true; }
constexpr bool done() const noexcept { return false; }
void operator()() const noexcept {}
void resume() const noexcept {}
void destroy() const noexcept {}
_Promise& promise() const
{
return *static_cast<_Promise*>(
__builtin_coro_promise(this->_M_fr_ptr, __alignof(_Promise), false));
}
private:
friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;
coroutine_handle() noexcept { this->_M_fr_ptr = (void*) &__noop_coro_fr; }
};
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
inline noop_coroutine_handle noop_coroutine() noexcept
{
return noop_coroutine_handle();
}
struct suspend_always
{
constexpr bool await_ready() const noexcept { return false; }
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
struct suspend_never
{
constexpr bool await_ready() const noexcept { return true; }
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
}
}
#endif
class Task;
class Promise {
public:
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
Promise() noexcept = default;
Task get_return_object() noexcept;
void unhandled_exception() noexcept ;
void return_value(int&& value) ;
};
class Task {
public:
using promise_type = Promise;
using handle_t = std::coroutine_handle<promise_type>;
Task(const Task& t) = delete;
Task(Task&& t) noexcept ;
~Task() ;
Task& operator=(Task t) noexcept ;
};
Task Foo() {
co_return ({ static int frame = 0; 0; });
}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs