Issue 147150
Summary `CoyieldExpr` doesn't contain the original AST `-ast-print` returns invalid source.
Labels new issue
Assignees
Reporter hanickadot
    Following code when parsed and emitted with `-ast-print` returns wrong result:

```c++
simple_coro<int> coro_test() {
  co_yield 2001;
  co_return 2010;
  co_await my_awaitable{2061};
}
```

Result printed by clang is: (with fixed formatting
```c++
simple_coro<int> coro_test() {
  co_yield __promise.yield_value(2001); // <-- ERROR HERE
  co_return 2010;
  co_await my_awaitable{2061};
}
```

Expected result:
```c++
simple_coro<int> coro_test() {
  co_yield 2001;
  co_return 2010;
  co_await my_awaitable{2061};
}
```

Notice the `co_yield __promise.yield_value(1997);` it contains call to `__promise.yield_value` function, this helper AST is generated in `SemaCoroutine.cpp` in `Sema::ActOnCoyieldExpr`:
```c++
  // Build yield_value call.
  ExprResult Awaitable = buildPromiseCall(
      *this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
  if (Awaitable.isInvalid())
    return ExprError();

  // Build 'operator co_await' call.
  Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
  if (Awaitable.isInvalid())
    return ExprError();
```

There is Operand slot inside `CoroutineSuspendExpr` which should contain original _expression_, but the function `BuildCoyieldExpr` is already getting modified AST.

Full source code to repeat the problem:
```c++
#include <coroutine>

struct my_awaitable {
  int value;
  bool await_ready() const {
    return true;
  }
  void await_suspend(std::coroutine_handle<void>) {
    
  }
  int await_resume() const {
    return value;
  }
};

template <typename T> struct simple_coro {
	struct promise_type {
		T value{0};

		constexpr auto initial_suspend() const noexcept {
			return std::suspend_never{};
		}
		constexpr auto final_suspend() const noexcept {
			return std::suspend_never{};
		}
		constexpr void return_value(int v) noexcept {
      value = v;
		}
		constexpr auto yield_value(T v) noexcept {
      value = v;
			return std::suspend_always{};
		}
		std::coroutine_handle<promise_type> get_return_object() {
			return std::coroutine_handle<promise_type>::from_promise(*this);
		}
		constexpr void unhandled_exception() const noexcept {
		}
	};

private:
	std::coroutine_handle<promise_type> handle;

public:
	constexpr simple_coro(std::coroutine_handle<promise_type> h) noexcept: handle{h} { }
	constexpr ~simple_coro() noexcept {
		handle.destroy();
	}
	constexpr int get() {
		return handle.promise().value;
	}
};

simple_coro<int> coro_test() {
 co_yield 2001;
  co_return 2010;
  co_await my_awaitable{2061};
}
```

Maybe this is fine, but AFAIK clang is trying to represent the AST so the original source code is recoverable and this breaks it.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to