Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cxx-qt-build: do not panic for cxx_gen failures instead use Result #461

Merged
merged 1 commit into from
May 18, 2023

Conversation

ahayzen-kdab
Copy link
Collaborator

This allows for CXX errors to appear with a span in the macro expansion

Before this change if you had a unsupported type in an invokable only the following error would occur.

[build]   thread 'main' panicked at 'Could not generate C++ from Rust file:
Syn(Error("unsupported type: QUrl"))', crates/cxx-qt-build/src/lib.rs:120:14

Now with this change we have an additional error from the macro expansion.

[build] error: unsupported type: QUrl
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:57:35
[build]    |
[build] 57 |         pub fn test(&self, _url: &QUrl) {
[build]    |                                   ^^^^

Note however this does cause loads of extra errors below but this is a side effect of the rest of the CXX macro not being expanded, this first error is the correct one though.

Related to #38

@ahayzen-kdab
Copy link
Collaborator Author

FWIW to test this i added the following method to the minimal example without the extern block for the QUrl so it is missing.

        #[qinvokable]
        pub fn test(&self, _url: &QUrl) {

        }

Then this is the full error, you can see how the first error is the correct one, the others are a side effect of the CXX expansion not occurring as it failed - I don't think we can silence these as these are from the Rust compiler itself trying to build the code with the failed expansion ? But this is already way better than before :-)

Full error

[build] warning: cxx-qt-build failed to parse cxx_qt::bridge: Cxx(Syn(Error("unsupported type: QUrl")))
[build] error: unsupported type: QUrl
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:57:35
[build]    |
[build] 57 |         pub fn test(&self, _url: &QUrl) {
[build]    |                                   ^^^^
[build] 
[build] error[E0432]: unresolved import `super::my_object`
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:12:5
[build]    |
[build] 12 | mod my_object {
[build]    |     ^^^^^^^^^ could not find `my_object` in `super`
[build] 
[build] error[E0433]: failed to resolve: use of undeclared type `QString`
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:37:25
[build]    |
[build] 37 |                 string: QString::from(""),
[build]    |                         ^^^^^^^
[build]    |                         |
[build]    |                         use of undeclared type `QString`
[build]    |                         help: a struct with a similar name exists: `String`
[build]    |
[build]    = note: consider importing this struct:
[build]            cxx_qt_lib::QString
[build] 
[build] error[E0412]: cannot find type `QString` in this scope
[build]    --> examples/qml_minimal/rust/src/cxxqt_object.rs:28:17
[build]     |
[build] 28  |         string: QString,
[build]     |                 ^^^^^^^ help: a struct with a similar name exists: `String`
[build]     |
[build]    ::: /var/home/andrew/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/string.rs:367:1
[build]     |
[build] 367 | pub struct String {
[build]     | ----------------- similarly named struct `String` defined here
[build]     |
[build]     = note: consider importing this struct:
[build]             cxx_qt_lib::QString
[build] 
[build] error[E0412]: cannot find type `MyObjectQt` in this scope
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:11:1
[build]    |
[build] 11 | #[cxx_qt::bridge]
[build]    | ^^^^^^^^^^^^^^^^^ not found in this scope
[build]    |
[build]    = note: this error originates in the attribute macro `cxx_qt::bridge` (in Nightly builds, run with -Z macro-backtrace for more info)
[build] 
[build] error[E0412]: cannot find type `QString` in this scope
[build]    --> examples/qml_minimal/rust/src/cxxqt_object.rs:52:39
[build]     |
[build] 52  |         pub fn say_hi(&self, string: &QString, number: i32) {
[build]     |                                       ^^^^^^^ help: a struct with a similar name exists: `String`
[build]     |
[build]    ::: /var/home/andrew/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/string.rs:367:1
[build]     |
[build] 367 | pub struct String {
[build]     | ----------------- similarly named struct `String` defined here
[build]     |
[build]     = note: consider importing this struct:
[build]             cxx_qt_lib::QString
[build] 
[build] error[E0412]: cannot find type `QUrl` in this scope
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:57:35
[build]    |
[build] 57 |         pub fn test(&self, _url: &QUrl) {
[build]    |                                   ^^^^ not found in this scope
[build]    |
[build]    = note: consider importing this struct:
[build]            cxx_qt_lib::QUrl
[build] 
[build] error[E0412]: cannot find type `MyObjectCxxQtThread` in this scope
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:11:1
[build]    |
[build] 11 | #[cxx_qt::bridge]
[build]    | ^^^^^^^^^^^^^^^^^ not found in this scope
[build]    |
[build]    = note: this error originates in the attribute macro `cxx_qt::bridge` (in Nightly builds, run with -Z macro-backtrace for more info)
[build] 
[build] error[E0412]: cannot find type `MyObjectQt` in module `super`
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:11:1
[build]    |
[build] 11 | #[cxx_qt::bridge]
[build]    | ^^^^^^^^^^^^^^^^^ help: a struct with a similar name exists: `MyObject`
[build] ...
[build] 24 |     pub struct MyObject {
[build]    |     ------------------- similarly named struct `MyObject` defined here
[build]    |
[build]    = note: this error originates in the attribute macro `cxx_qt::bridge` (in Nightly builds, run with -Z macro-backtrace for more info)
[build] 
[build] Some errors have detailed explanations: E0412, E0432, E0433.
[build] For more information about an error, try `rustc --explain E0412`.
[build] The following warnings were emitted during compilation:
[build] 
[build] warning: cxx-qt-build failed to parse cxx_qt::bridge: Cxx(Syn(Error("unsupported type: QUrl")))

@ahayzen-kdab ahayzen-kdab force-pushed the 38-cxx-gen-errors-do-not-panic branch from feaab7b to 5f7f58b Compare March 3, 2023 13:46
@LeonMatthesKDAB
Copy link
Collaborator

Hm, I'm currently looking into how CXX generates it's own errors.
The weird thing is that they actually do exit the build script unsuccessfully from what I can tell...

However, I then still get perfect error messages in rust_analyzer 🤔

I wonder if there's some output from cxx-build that cargo or rust-analyzer can actually understand to provide these nicer diagnostics 🤔

Output if I add a code similar to your example somewhere in cxx-qt-lib:

Full build script output
    Compiling cxx-qt-lib v0.4.1 (/home/kdab/Documents/projects/3371-Rust-RnD/cxx-qt/crates/cxx-qt-lib)
The following warnings were emitted during compilation:

warning: Could not open /usr/lib64/libQt6Qml.prl file to read libraries to link: No such file or directory (os error 2)

error: failed to run custom build command for `cxx-qt-lib v0.4.1 (/home/kdab/Documents/projects/3371-Rust-RnD/cxx-qt/crates/cxx-qt-lib)`

Caused by:
  process didn't exit successfully: `/home/kdab/Documents/projects/3371-Rust-RnD/cxx-qt/target/debug/build/cxx-qt-lib-c0bcb22de1a2c254/build-script-build` (exit status: 1)
  --- stdout
  cargo:rerun-if-env-changed=QMAKE
  cargo:rerun-if-env-changed=QT_VERSION_MAJOR
  cargo:rustc-link-search=/usr/lib64
  cargo:rustc-link-lib=Qt6Core
  cargo:rustc-link-lib=Qt6Gui
  cargo:rustc-link-lib=Qt6Qml
  cargo:warning=Could not open /usr/lib64/libQt6Qml.prl file to read libraries to link: No such file or directory (os error 2)
  cargo:rustc-cfg=qt_version_major="6"
  cargo:rerun-if-changed=src/core/qbytearray.rs
  cargo:rerun-if-changed=src/core/qcoreapplication.rs
// ....
  cargo:rerun-if-changed=src/qml/qqmlapplicationengine.rs
  cargo:rerun-if-changed=src/qml/qqmlengine.rs

  --- stderr

  error[cxxbridge]: unsupported type: QTest
     ┌─ src/core/qdatetime.rs:31:24
     │
  31 │         fn test(qurl: &QTest);
     │                        ^^^^^ unsupported type

@ahayzen-kdab
Copy link
Collaborator Author

@LeonMatthesKDAB does CXX error or warn ? As note out build script only warns at the moment ?

@LeonMatthesKDAB
Copy link
Collaborator

CXX errors, the build script actually fails.

I think this might be the code responsible for doing this:

pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

@LeonMatthesKDAB
Copy link
Collaborator

It does not panic though, but rather just return a non-zero exit code...
I don't really see what that would change though...

@ahayzen-kdab
Copy link
Collaborator Author

Fun, so what happens if you do the same with cxx-qt-build ? As it might instruct the rust compiler to try not to build the Rust code but only to perform macro expansion or something 🤷

@LeonMatthesKDAB
Copy link
Collaborator

The strange thing is that I don't see this cxxbridge::error text exactly in the stderr output of CXX.
So it's possible something else is going on 🤔

There's also some machinery in this report function that I don't really understand :/

@ahayzen-kdab
Copy link
Collaborator Author

The build script output isn't always shown in the console as it's an input to cargo.

@ahayzen-kdab
Copy link
Collaborator Author

I wonder if in the bridge code

    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })

Where the report(err) occurs, is this writing out the text in a way that appears like it's coming from the macro expansion phase?

pub(crate) fn report(error: impl StdError) -> impl Display {
    struct Report<E>(E);

    impl<E: StdError> Display for Report<E> {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            write!(formatter, "{}", self.0)?;
            let mut error: &dyn StdError = &self.0;

            while let Some(cause) = error.source() {
                write!(formatter, "\n\nCaused by:\n    {}", cause)?;
                error = cause;
            }

            Ok(())
        }
    }

    Report(error)
}

@ahayzen-kdab
Copy link
Collaborator Author

Hmm but then the cause goes missing and we only get cxx_qt error: unsupported type: QUrl under the stderr part of output. Maybe we aren't enabling a feature or something 🤷

@ahayzen-kdab
Copy link
Collaborator Author

And it's definitely stopping at cxx_build::bridges in your cxx-qt-lib example

@ahayzen-kdab
Copy link
Collaborator Author

Yup so the source() is None when i try the same code for us, error: Cxx(Syn(Error("unsupported type: QUrl"))), source: None. Maybe something in cxx_gen is causing this vs using cxx_build ?

@ahayzen-kdab ahayzen-kdab added this to the 0.6 milestone Mar 7, 2023
@LeonMatthesKDAB
Copy link
Collaborator

So, what I've found.
When rust_analyzer runs the build script, the output it gets is from cargo check, with the --output-format=json.
If I do this, I'll get some json messages on stdout, as well as cargo's error message that the build script failed on stderror.
I can't find the error message in that output though...
So I don't think this is where rust_analyzer gets the error message from.

More and more I suspect that that rust_analyzer for some reason still continues with macro expansion, even though the build script failed. I just don't know why it does it for CXX, but not for CXX-Qt.

@Be-ing
Copy link
Contributor

Be-ing commented Mar 15, 2023

It may be worth reaching out to the rust-analyzer maintainers for advice how to handle this.

@LeonMatthesKDAB
Copy link
Collaborator

LeonMatthesKDAB commented Mar 16, 2023

WTF...

I'm just testing diagnostics on our current main.
They just work with rust_analyzer!

The output of cmake --build is still pretty cryptic:

thread 'main' panicked at 'Could not generate C++ from Rust file: Syn(Error("unsupported type: QUrl"))', crates/cxx-qt-build/src/lib.rs:127:14

But that is something that CXX fixes using the codespan-reporting anyway, which we can use as well...

See:
image

I do however, also get this error:
image

Which I'm not certain where that's coming from.

@LeonMatthesKDAB
Copy link
Collaborator

It definitely also works with our own errors as well:
image

So maybe we don't need this change and only need to pretty-print our own diagnostics in the build script???

@LeonMatthesKDAB
Copy link
Collaborator

LeonMatthesKDAB commented Mar 16, 2023

It even works with diagnostics inside qinvokable methods...
image

However, they only show up after the file has been saved.
I think this is because rust_analyzer runs cargo check on save, and doesn't have complete diagnostics without this feature.
See rust-lang/rust-analyzer#3107
Note that I do have rust-analyzers experimental diagnostics enabled. (rust-analyzer.diagnostics.experimental.enable=true)

Also, it generates a diagnostic on the macro itself:
image

Probably because one of the diagnostic Spans is pointing to output of our macro.

@LeonMatthesKDAB
Copy link
Collaborator

So, I've got the basic diagnostic display going from our build script:

image

@ahayzen-kdab ahayzen-kdab force-pushed the 38-cxx-gen-errors-do-not-panic branch from d072ef9 to c94b177 Compare May 18, 2023 13:57
This allows for CXX errors to appear with a span in the macro expansion

Before this change if you had a unsupported type in an invokable only
the following error would occur.

```
[build]   thread 'main' panicked at 'Could not generate C++ from Rust file:
Syn(Error("unsupported type: QUrl"))', crates/cxx-qt-build/src/lib.rs:120:14
```

Now with this change we have an additional error from the macro expansion.

```
[build] error: unsupported type: QUrl
[build]   --> examples/qml_minimal/rust/src/cxxqt_object.rs:57:35
[build]    |
[build] 57 |         pub fn test(&self, _url: &QUrl) {
[build]    |                                   ^^^^
```

Related to KDAB#38
@ahayzen-kdab ahayzen-kdab force-pushed the 38-cxx-gen-errors-do-not-panic branch from c94b177 to 0c1f8a6 Compare May 18, 2023 14:04
Copy link
Collaborator

@LeonMatthesKDAB LeonMatthesKDAB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ahayzen-kdab ahayzen-kdab enabled auto-merge (rebase) May 18, 2023 14:21
@ahayzen-kdab ahayzen-kdab merged commit 9d86f73 into KDAB:main May 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants