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

Unexpected token: expected ;, found #. #106020

Closed
Jerrody opened this issue Dec 21, 2022 · 10 comments · Fixed by #117988
Closed

Unexpected token: expected ;, found #. #106020

Jerrody opened this issue Dec 21, 2022 · 10 comments · Fixed by #117988
Labels
A-parser Area: The parsing of Rust source code to an AST D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Jerrody
Copy link
Contributor

Jerrody commented Dec 21, 2022

#[cfg(feature = "validation")]
[debug_utils_ext, (*surface_extensions).to_owned()].concat()

#[cfg(not(feature = "validation"))]
surface_extensions.to_owned()

Error code:

error: expected `;`, found `#`
  --> src\engine\renderer\context\instance.rs:44:73
   |
44 |             [debug_utils_ext, (*surface_extensions).to_owned()].concat()
   |                                                                         ^ help: add `;` here
45 |
46 |             #[cfg(not(feature = "validation"))]
   |             - unexpected token

Metadata:

rustc 1.67.0-nightly (e1d819583 2022-12-05)
binary: rustc
commit-hash: e1d819583f0bf13b016b119c1c2c43e6d3979450
commit-date: 2022-12-05
host: x86_64-pc-windows-msvc
release: 1.67.0-nightly
LLVM version: 15.0.4
@Jerrody Jerrody added the C-bug Category: This is a bug. label Dec 21, 2022
@Jerrody Jerrody changed the title Unexpected token: expected ;, found #`. Unexpected token: expected ;, found #. Dec 21, 2022
@compiler-errors
Copy link
Member

What is the issue you are reporting here @Jerrody ?

@Jerrody
Copy link
Contributor Author

Jerrody commented Dec 21, 2022

What is the issue you are reporting here @Jerrody ?

Well, I thought that compiler can understand that #[cfg()] is related to the block of code, but it fails.

@Noratrieb
Copy link
Member

Noratrieb commented Dec 22, 2022

Can you post a minimal reproducible example that demonstrates your issue? Or at least mention exactly what you'd expect to happen and why.

Even code that is cfged out is still required to parse successfully.

@Jerrody
Copy link
Contributor Author

Jerrody commented Dec 22, 2022

Can you post a minimal reproducible example that demonstrates your issue? Or at least mention exactly what you'd expect to happen and why.

Even code that is cfged out is still required to parse successfully.

Let's show you what exactly problem I have.
Full code:

let instance_extensions = {
    let surface_extensions =
        ash_window::enumerate_required_extensions(window.raw_display_handle()).track()?;

    #[cfg(feature = "validation")]
    let debug_utils_ext = vec![ash::extensions::ext::DebugUtils::name().as_ptr()];

    #[cfg(feature = "validation")]
    [debug_utils_ext, (*surface_extensions).to_owned()].concat()

    #[cfg(not(feature = "validation"))]
    surface_extensions.to_owned()
};

And I get this error:

error: expected `;`, found `#`
  --> src\engine\renderer\context\instance.rs:44:73
   |
44 |             [debug_utils_ext, (*surface_extensions).to_owned()].concat()
   |                                                                         ^ help: add `;` here
45 |
46 |             #[cfg(not(feature = "validation"))]
   |             - unexpected token

@SkiFire13
Copy link
Contributor

You seem to already have posted this in this discussion in the internals forum a month ago. What you're asking seems a rather big change to me, I'm not that familiar with how the compiler parser works but I believe it currently requires your program syntax to be correct before #[cfg(...)] macros are expanded, which is not true for your example, so some fundamental changes would be needed.

@Jerrody
Copy link
Contributor Author

Jerrody commented Dec 22, 2022

You seem to already have posted this in this discussion in the internals forum a month ago. What you're asking seems a rather big change to me, I'm not that familiar with how the compiler parser works but I believe it currently requires your program syntax to be correct before #[cfg(...)] macros are expanded, which is not true for your example, so some fundamental changes would be needed.

Oh, damn, sorry. I totally forgot that I made a post.
Well, if it's not a bug and parser works like this it is bad, anyway, exists alternative way to write like this.
But for me my issue is a candidate to feature request or a bug. Anyway, I'm not a lang dev, so I don't know what scales of this defect (?).

@lukas-code
Copy link
Member

The workaround for this is to wrap the expressions in a block:

let instance_extensions = {
    let surface_extensions =
        ash_window::enumerate_required_extensions(window.raw_display_handle()).track()?;

    #[cfg(feature = "validation")]
    let debug_utils_ext = vec![ash::extensions::ext::DebugUtils::name().as_ptr()];

    #[cfg(feature = "validation")]
    { [debug_utils_ext, (*surface_extensions).to_owned()].concat() }

    #[cfg(not(feature = "validation"))]
    { surface_extensions.to_owned() }
};

@Jerrody
Copy link
Contributor Author

Jerrody commented Dec 22, 2022

The workaround for this is to wrap the expressions in a block:

let instance_extensions = {
    let surface_extensions =
        ash_window::enumerate_required_extensions(window.raw_display_handle()).track()?;

    #[cfg(feature = "validation")]
    let debug_utils_ext = vec![ash::extensions::ext::DebugUtils::name().as_ptr()];

    #[cfg(feature = "validation")]
    { [debug_utils_ext, (*surface_extensions).to_owned()].concat() }

    #[cfg(not(feature = "validation"))]
    { surface_extensions.to_owned() }
};

I solved this issue exactly as you did.

@albertlarsan68
Copy link
Member

Another way to do this is using the cfg! macro and if ... else.
I personally thinks it is more clear, and should optimize the same.

let instance_extensions = {
    let surface_extensions =
        ash_window::enumerate_required_extensions(window.raw_display_handle()).track()?;

    #[cfg(feature = "validation")]
    let debug_utils_ext = vec![ash::extensions::ext::DebugUtils::name().as_ptr()];

    if cfg!(feature = "validation") {
        [debug_utils_ext, (*surface_extensions).to_owned()].concat()
    } else {
        surface_extensions.to_owned()
    }
};

@Jerrody
Copy link
Contributor Author

Jerrody commented Dec 24, 2022

Another way to do this is using the cfg! macro and if ... else. I personally thinks it is more clear, and should optimize the same.

let instance_extensions = {
    let surface_extensions =
        ash_window::enumerate_required_extensions(window.raw_display_handle()).track()?;

    #[cfg(feature = "validation")]
    let debug_utils_ext = vec![ash::extensions::ext::DebugUtils::name().as_ptr()];

    if cfg!(feature = "validation") {
        [debug_utils_ext, (*surface_extensions).to_owned()].concat()
    } else {
        surface_extensions.to_owned()
    }
};

Work is not the same, due to cfg! compile-time evaluating an expression that we pass in it and evaluates only it, but at the same time everything compiles what is inside of if else.

@estebank estebank added A-parser Area: The parsing of Rust source code to an AST T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. D-confusing Diagnostics: Confusing error or lint that should be reworked. and removed C-bug Category: This is a bug. labels Mar 14, 2023
compiler-errors added a commit to compiler-errors/rust that referenced this issue Nov 20, 2023
Handle attempts to have multiple `cfg`d tail expressions

When encountering code that seems like it might be trying to have multiple tail expressions depending on `cfg` information, suggest alternatives that will success to parse.

```rust
fn foo() -> String {
    #[cfg(feature = "validation")]
    [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
    #[cfg(not(feature = "validation"))]
    String::new()
}
```

```
error: expected `;`, found `#`
  --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
   |
LL |     #[cfg(feature = "validation")]
   |     ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
   |                                                                ^ expected `;` here
LL |     #[cfg(not(feature = "validation"))]
   |     - unexpected token
   |
help: add `;` here
   |
LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
   |                                                                +
help: alternatively, consider surrounding the expression with a block
   |
LL |     { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
   |     +                                                             +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
   |
LL ~     if cfg!(feature = "validation") {
LL ~         [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~     } else if cfg!(not(feature = "validation")) {
LL ~         String::new()
LL +     }
   |
```

Fix rust-lang#106020.

r? `@oli-obk`
@bors bors closed this as completed in a16722d Nov 20, 2023
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Nov 20, 2023
Rollup merge of rust-lang#117988 - estebank:issue-106020, r=cjgillot

Handle attempts to have multiple `cfg`d tail expressions

When encountering code that seems like it might be trying to have multiple tail expressions depending on `cfg` information, suggest alternatives that will success to parse.

```rust
fn foo() -> String {
    #[cfg(feature = "validation")]
    [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
    #[cfg(not(feature = "validation"))]
    String::new()
}
```

```
error: expected `;`, found `#`
  --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
   |
LL |     #[cfg(feature = "validation")]
   |     ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
   |                                                                ^ expected `;` here
LL |     #[cfg(not(feature = "validation"))]
   |     - unexpected token
   |
help: add `;` here
   |
LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
   |                                                                +
help: alternatively, consider surrounding the expression with a block
   |
LL |     { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
   |     +                                                             +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
   |
LL ~     if cfg!(feature = "validation") {
LL ~         [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~     } else if cfg!(not(feature = "validation")) {
LL ~         String::new()
LL +     }
   |
```

Fix rust-lang#106020.

r? `@oli-obk`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parser Area: The parsing of Rust source code to an AST D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants