hsutter / cppfront

A personal experimental C++ Syntax 2 -> Syntax 1 compiler

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Issue with the newly added "identifier : const = value " functionality

HALL9kv0 opened this issue · comments

Describe the bug

The identifier : const = value functionality is not consistent. 1) Doesn't work at all in global/namespace scope (might be a feature, not a bug) and 2) it results in a g++ error when trying to initialize an std::array, even though it is used inside the main scope (probably a bug).

To Reproduce

A) The following works:

N : const int =2;

main: () -> int = {
   arr: std::array<int,N> =();
}

B) This one also works:

main: () -> int = {
N : const  =2;
}

C) The following results to a cppfront error :

N : const =2;

main: () -> int = {
   arr: std::array<int,N> =();
}

error: namespace scope objects must have a concrete type, not a deduced type

D) Then when I make the declaration inside the main function scope, it compiles to cpp but we get a g++ error.

main: () -> int = {
    N : const =2;

   arr: std::array<int,N> =();
}

error: the value of ‘N’ is not usable in a constant expression
7 | arr: std::array<int,N> =();
| ~~~~~~~~~~^~
main.cpp2:5:6: note: ‘int N’ is not const
5 | N : const =2;
| ^
main.cpp2:7:29: note: in template argument for type ‘long unsigned int’
7 | arr: std::array<int,N> =();

and the cpp file is :

[[nodiscard]] auto main() -> int{
    auto N {2}; 

   std::array<int,cpp2::move(N)> arr {}; 
}

Command lines including which C++ compiler you are using:
cppfront -p main.cpp2 && g++ -std=c++23 main.cpp

Expected result
The auto N {2}; to be a const in the cpp file.

As a user, I expected to be able to write N: const =2 in the global/namespace scope also, and to be able to use it to initialize the std::array.
If I'm not mistaken, case D is indeed a bug, but case C is a feature, as namespace objects cannot have a deduced type.

Should we have an exception to the rule regarding the C case, when the expression is const/constexpr?

Just to expand on case D) above, this Cpp2:

main: () -> int = {
    a: const _ = 1;
    b: const   = 2;
}

lowers to:

[[nodiscard]] auto main() -> int{
    auto const a {1}; 
    auto b {2}; 
}

Repro on Godbolt

From my closed pr (referring to case D):
d0836be suppresses the error, but returning a default object drops the pc_qualifiers.

Due to cppfront's being a backtracking parser, it does the hokey pokey, entering and exiting parse sections until it's successful, and with my adjustment of defaulting to return the built up type_id node all the time, the parser gets thrown off in the instances where it is just testing waters by trying to parse a type id. It would be nice to convert cppfront to a predictive parser (nothing in the grammar stands out as an obstacle), but at this stage, that would be quite the undertaking.

The identifier : const = value functionality is not consistent. 1) Doesn't work at all in global/namespace scope (might be a feature, not a bug)

Correct, as the error message says, no deduced type at global/namespace scope. You get the same error for N := 2.

Thanks! These are not really related to the const change, they are about other rules:

C) The following results to a cppfront error :

N : const =2;

main: () -> int = {
   arr: std::array<int,N> =();
}

error: namespace scope objects must have a concrete type, not a deduced type

Correct, this is as intended. Namespace-scope objects cannot have deduced types (for various reasons including order independence), and writing just const still requests to deduce the type.

D) Then when I make the declaration inside the main function scope, it compiles to cpp but we get a g++ error.

main: () -> int = {
    N : const =2;

   arr: std::array<int,N> =();
}

Correct, this one is just because you can't use a run-time object as a compile-time template argument. The fix is easy though... just as in Cpp1 you'd have to write constexpr on the declaration of N, in Cpp2 you change = to == (pronounced "is always equal to") which does the same thing and emits constexpr, and then you don't need the const because it's implied by ==. This code works fine:

main: () = {
    N :== 2;
    arr: std::array<int,N> =();
}

Thanks again for the good questions!

@hsutter #1138 (comment) is still a separate issue.

Reopening for this (thanks Neil, and Greg for remind me):

main: () -> int = {
    a: const _ = 1;
    b: const   = 2;
}

lowers to:

[[nodiscard]] auto main() -> int{
    auto const a {1}; 
    auto b {2}; 
}

Now that's fixed too, thanks!