Skip to content

[BUG]  #792

Closed
Closed

Description

@iprtel

Describe the bug
cppfront produces CPP1 code that is no accepted by gcc-11.4 or clang-18.0.0

To Reproduce

  1. in issue_base.h
class IssueBase {
public:
    virtual bool virtualConstFunction() const = 0;
    virtual bool virtualFunction() = 0;
};
  1. in issue.cpp2
#include "issue_base.h"
Issue : type = {
    virtualConstFunction : (this) -> bool = {
        std::cout << "virtual const function called\n";
        return true;
    }
    virtualFunction : (inout this) -> bool = {
        std::cout << "virtual function called\n";
        return false;
    }
}

main : () = {
    issue : Issue = ();
    issue.virtualFunction();
    issue.virtualConstFunction();
    issue.virtualFunction();
}

Cppfront generates std::move(issue) for the last use of issue in main. This works fine if virtualConstFunction is the last function called but fails if virtualFunction is the last call.

gcc-11.4.0:

[proc] Executing command: /usr/bin/cmake --build /workspaces/cpp2_learn/build --config Debug --target issue -j 10 --
[build] [1/3 33% :: 0.007] Generating ../_cppfront/issue.cpp
[build] /workspaces/cpp2_learn/issue/issue.cpp2... ok (mixed Cpp1/Cpp2, Cpp2 code passes safety checks)
[build]
[build] [2/3 66% :: 1.423] Building CXX object issue/CMakeFiles/issue.dir//_cppfront/issue.cpp.o
[build] FAILED: issue/CMakeFiles/issue.dir/
/_cppfront/issue.cpp.o
[build] /usr/bin/g++ -I/workspaces/cpp2_learn/issue -isystem /workspaces/cpp2_learn/cppfront/cppfront/include -g -std=gnu++20 -MD -MT issue/CMakeFiles/issue.dir//_cppfront/issue.cpp.o -MF issue/CMakeFiles/issue.dir//_cppfront/issue.cpp.o.d -o issue/CMakeFiles/issue.dir/__/_cppfront/issue.cpp.o -c /workspaces/cpp2_learn/build/_cppfront/issue.cpp
[build] In file included from /workspaces/cpp2_learn/build/_cppfront/issue.cpp:7:
[build] /workspaces/cpp2_learn/issue/issue.cpp2: In instantiation of 'main()::<lambda(auto:80&&)> [with auto:80 = Issue]':
[build] /workspaces/cpp2_learn/issue/issue.cpp2:19:5: required from here
[build] /workspaces/cpp2_learn/issue/issue.cpp2:19:5: error: 'virtualFunction' was not declared in this scope
[build] 19 | issue.virtualFunction();
[build] | ^
[build] ninja: build stopped: subcommand failed.

clang-18.0.0:

[build] [1/3 33% :: 0.006] Generating ../_cppfront/issue.cpp
[build] /workspaces/cpp2_learn/issue/issue.cpp2... ok (mixed Cpp1/Cpp2, Cpp2 code passes safety checks)
[build]
[build] [2/3 66% :: 1.704] Building CXX object issue/CMakeFiles/issue.dir//_cppfront/issue.cpp.o
[build] FAILED: issue/CMakeFiles/issue.dir/
/_cppfront/issue.cpp.o
[build] /usr/bin/clang++-18 -I/workspaces/cpp2_learn/issue -isystem /workspaces/cpp2_learn/cppfront/cppfront/include -g -std=gnu++20 -MD -MT issue/CMakeFiles/issue.dir//_cppfront/issue.cpp.o -MF issue/CMakeFiles/issue.dir//_cppfront/issue.cpp.o.d -o issue/CMakeFiles/issue.dir/__/_cppfront/issue.cpp.o -c /workspaces/cpp2_learn/build/_cppfront/issue.cpp
[build] /workspaces/cpp2_learn/issue/issue.cpp2:19:17: error: use of undeclared identifier 'virtualFunction'
[build] 19 | CPP2_UFCS_0(virtualFunction, std::move(issue));
[build] | ^
[build] /workspaces/cpp2_learn/issue/issue.cpp2:19:5: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()' requested here
[build] 19 | CPP2_UFCS_0(virtualFunction, std::move(issue));
[build] | ^
[build] /workspaces/cpp2_learn/cppfront/cppfront/include/cpp2util.h:797:2: note: expanded from macro 'CPP2_UFCS_0'
[build] 797 | }(PARAM1)
[build] | ^
[build] 1 error generated.
[build] ninja: build stopped: subcommand failed.

The generated main:

#line 14 "/workspaces/cpp2_learn/issue/issue.cpp2"
auto main() -> int{
    Issue issue {}; 

    CPP2_UFCS_0(virtualFunction, issue);
    CPP2_UFCS_0(virtualConstFunction, issue);
    CPP2_UFCS_0(virtualFunction, std::move(issue));
}

If the std::move(...) is removed around issue both compilers accept the code.

Activity

  1. JohelEGP commented on Oct 30, 2023

    @JohelEGP
    Contributor

    For the implicit move, see #305 (comment).
    You need to add _ = issue;.

    To actually declare Issue as an IssueBase,
    you need a this: IssueBase; data member.
    To override the virtual functions,
    you need override this and override inout this parameters.

  2. iprtel commented on Oct 30, 2023

    @iprtel
    ContributorAuthor

    Thanks. So my simplified test case is issue.cpp2. I still get the same error.

    Issue : type = {
        constFunction : (this) -> bool = {
            std::cout << "const function called\n";
            return true;
        }
        nonConstFunction : (inout this) -> bool = {
            std::cout << "non const function called\n";
            return false;
        }
    }
    
    main : () = {
        issue : Issue = ();
        _ = issue.nonConstFunction();
        _ = issue.constFunction();
        _ = issue.nonConstFunction();
    }
    

    Thanks for the help on the inheritance. I struggled with that.

  3. JohelEGP commented on Oct 30, 2023

    @JohelEGP
    Contributor

    You need to discard the last use of issue, without any calls.

    You need to add _ = issue;.

  4. iprtel commented on Oct 30, 2023

    @iprtel
    ContributorAuthor

    So if the last function you called is non-const you need to discard the object.
    Thanks.

  5. iprtel commented on Oct 30, 2023

    @iprtel
    ContributorAuthor

    @JohelEGP sorry to come once again.
    My understanding about the discarding after the last non-const call is not sufficient.
    This mainalso fixes the problem:

    main : () = {
        issue : Issue = ();
        _ = issue.nonConstFunction();
        _ = issue.constFunction();
        result : _ = issue.nonConstFunction();
        std::cout << result ;
    }
    

    Here the move is on result :

    #line 12 "/workspaces/cpp2_learn/issue/issue.cpp2"
    auto main() -> int{
        Issue issue {}; 
        static_cast<void>(CPP2_UFCS_0(nonConstFunction, issue));
        static_cast<void>(CPP2_UFCS_0(constFunction, issue));
        auto result {CPP2_UFCS_0(nonConstFunction, issue)}; 
        std::cout << std::move(result);
    }
    
  6. JohelEGP commented on Oct 30, 2023

    @JohelEGP
    Contributor

    Rvalues are convertible to reference to const,
    so printing << works because the rhs is taken by reference to const.

  7. iprtel commented on Oct 30, 2023

    @iprtel
    ContributorAuthor

    So why is the discard on issue no longer needed? I thought that it was necessary since the last call had inout this and so the object counts as return value that needs to be discarded.

  8. JohelEGP commented on Oct 30, 2023

    @JohelEGP
    Contributor

    operator<< typically looks like operator<<: (inout s: std::ostream, in x: T),
    so x accepts moved objects.

  9. iprtel commented on Oct 30, 2023

    @iprtel
    ContributorAuthor

    Thanks for the explenation. But I'm more interessted why

    main : () = {
        issue : Issue = ();
        result : _ = issue.nonConstFunction();
    }
    

    is fine. While

    main : () = {
        issue : Issue = ();
        _ = issue.nonConstFunction();
    }
    

    requires a _ = issue;

  10. JohelEGP commented on Oct 30, 2023

    @JohelEGP
    Contributor

    That must be #749.

  11. hsutter commented on Nov 14, 2023

    @hsutter
    Owner

    You're right, both should require _ = issue;. Will fix.

    The issue is that I was trying out suppressing move-from-last-use if the last use was in an initializer, because of examples like view: std::span = local_variable; when that was the last use of local_variable, which is an error for an rvalue. But that also suppresses a righteous move in examples like result := local_variable;. So I now agree those should be treated as rvalues too, and if that causes an error for an rvalue because there is no further us of that variable in scope, then the programmer must write an explicit discard of the variable.

  12. iprtel commented on Nov 19, 2023

    @iprtel
    ContributorAuthor

    Are you at all concerned that people will just put explicit discards all over the place when trying to fix a compilation problem that the don't understand fully?

  13. tomFlowee commented on Dec 20, 2023

    @tomFlowee

    lets continue this topic on #901

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions