microsoft / microsoft/vscode-cpptools

Wrong lookup of promise type with std::coroutine_traits and non-static member functions

Open
#10,568 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug Language Service verified Visual Studio
Dominant language
TypeScript
Stars
6.2k
Forks
1.7k
Avg merge
14h 46m
Merged PRs (30d)
61

Description

Environment
  • OS and Version: Windows 10, 10.0.19044
  • VS Code Version: 1.75.1 (user setup)
  • C/C++ Extension Version: 1.14.3
  • If using SSH remote, specify OS of remote machine: Debian 11/bullseye
Bug Summary and Steps to Reproduce

Bug Summary:
The C/C++ extension shows an error for coroutines implemented as non-static member functions when using the std::coroutine_traits to define the promise type. Consider the following minimal example:

#include <coroutine>

struct Resumable {
  std::coroutine_handle<> m_handle;
};

struct my_promise_type {
  bool m_ready = false;
  ~my_promise_type() { }
  
  Resumable get_return_object() { return {.m_handle = std::coroutine_handle<my_promise_type>::from_promise(*this)}; }
  std::suspend_always initial_suspend() { return {}; }
  std::suspend_always final_suspend() noexcept { return {}; }
  void unhandled_exception() { }
  void return_value(bool value) { m_ready = value; }
};

class Outer;

namespace std {
  template<typename... ARGS>
  struct coroutine_traits<Resumable, Outer &, ARGS...>{
    using promise_type = my_promise_type;
  };
}

class Outer {
public:
  Resumable coroutine() { co_return true; }
};

Outer c;
int main(){
    auto coro = c.coroutine();
    coro.m_handle.resume();
}

The example can be compiled with the command line

g++ -g -o minimal -fcoroutines -std=gnu++20 -O3 minimal.cpp

In this case, we define the promise_type of the Resumable struct using std::coroutine_traits. The documentation states that for coroutines defined as non-static member functions. ARGS must include the implicit object parameter, hence, struct coroutine_traits includes Outer & in the template parameter list.

The extension, however, shows the following error for the coroutine Outer::coroutine(), expecting the second parameter to be of type Outer * instead of the correct Outer &:

class "std::__n4861::coroutine_traits<Resumable, Outer *>" has no member "promise_type "C/C++(135)

Steps to reproduce:

  1. Open a file with the above contents in VS Code and the C/C++ extension installed as minimal.cpp.
  2. See error for Outer::coroutine()

Expected behavior:
The lookup for promise_type is done via std::__n4861::coroutine_traits<Resumable, Outer &>::promise_type instead of std::__n4861::coroutine_traits<Resumable, Outer *>.

Configuration and Logs

Contents of c_cpp_properties.json:

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/g++",
            "cStandard": "c17",
            "intelliSenseMode": "linux-gcc-x64",
            "cppStandard": "c++20"
        }
    ],
    "version": 4
}

Log Diagnostics:

-------- Diagnostics - 2/22/2023, 12:35:57 PM
Version: 1.14.3
Current Configuration:
{
    "name": "Linux",
    "includePath": [
        "${workspaceFolder}/**"
    ],
    "defines": [],
    "compilerPath": "/usr/bin/g++",
    "cStandard": "c17",
    "intelliSenseMode": "linux-gcc-x64",
    "cppStandard": "c++20",
    "compilerPathIsExplicit": true,
    "cStandardIsExplicit": true,
    "cppStandardIsExplicit": true,
    "intelliSenseModeIsExplicit": true
}
Translation Unit Mappings:
[ [...]/minimal.cpp ]:
    [...]/minimal.cpp
Translation Unit Configurations:
[ [...]/minimal.cpp ]:
    Process ID: 212752
    Memory Usage: 278 MB
    Compiler Path: /usr/bin/g++
    Includes:
        /usr/include/c++/10
        /usr/include/x86_64-linux-gnu/c++/10
        /usr/include/c++/10/backward
        /usr/lib/gcc/x86_64-linux-gnu/10/include
        /usr/local/include
        /usr/include/x86_64-linux-gnu
        /usr/include
    Standard Version: c++20
    IntelliSense Mode: linux-gcc-x64
    Other Flags:
        --g++
        --gnu_version=100201
Total Memory Usage: 278 MB

------- Workspace parsing diagnostics -------
Number of files discovered (not excluded): 7245

Language server log:

willSaveWaitUntil: 0ms
LSP: cpptools/fileChanged: file:///[...]/minimal.cpp
LSP: textDocument/didSave: file:///[...]/minimal.cpp
  tag parsing file: /[...]/minimal.cpp
idle loop: reparsing the active document
Checking for syntax errors: /[...]/minimal.cpp
Queueing IntelliSense update for files in translation unit of: /[...]/minimal.cpp
Error squiggle count: 1
Update IntelliSense time (sec): 0.255
LSP: cpptools/getSemanticTokens: file:///[...]/minimal.cpp (id: 8551)
LSP: cpptools/getFoldingRanges: file:///[...]/minimal.cpp (id: 8552)
LSP: cpptools/getCodeActions: file:///[...]/minimal.cpp (id: 8553)
Other Extensions
  • Remote - SSH
  • Remote Explorer
  • CMake
  • CMake Tools
Additional context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the diagnostic with the minimal.cpp example in VS Code using the supplied c_cpp_properties.json and C++20 configuration. Trace the coroutine promise lookup in the C/C++ extension's IntelliSense path; done means the example no longer reports an error and resolves coroutine_traits with Outer&.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.