Repository navigation
[BUG] UFCS fails during constant evaluation only #788
Copy link
Copy link
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Title: UFCS fails during constant evaluation only.
Description:
Given a parameter named after the function being called,
UFCS will fail during constant evaluation only
in the case UFCS would call a member function.
Minimal reproducer (https://cpp2.godbolt.org/z/jKWG4boaq, https://compiler-explorer.com/z/zeqW6MEPK):
t: @struct type = {
f: (this) -> int == 0;
}
g: (f) = {
[[assert: t().f() == 0]] // OK.
static_assert(t().f() == 0); // Error: Argument `f` isn't "`constexpr`".
}
main: () = {
g(0);
// g(std::identity()); // Might be OK since P2280R4 (unimplemented).
}
Commands:
cppfront main.cpp2
clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -I . main.cppExpected result: A well-formed program that calls the member function.
Actual result and error:
Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================
#include "cpp2util.h"
class t;
//=== Cpp2 type definitions and function declarations ===========================
class t {
public: [[nodiscard]] constexpr auto f() const& -> int;
};
auto g(auto const& f) -> void;
auto main() -> int;
//=== Cpp2 function definitions =================================================
[[nodiscard]] constexpr auto t::f() const& -> int { return 0; }
auto g(auto const& f) -> void{
cpp2::Default.expects(CPP2_UFCS_0(f, t()) == 0, "");// OK.
static_assert(CPP2_UFCS_0(f, t()) == 0);// Error: Argument `f` isn't "`constexpr`".
}
auto main() -> int{
g(0);
// g(std::identity()); // Might be OK since P2280R4 (unimplemented).
}Output:
main.cpp2:7:17: error: static assertion expression is not an integral constant expression
7 | static_assert(CPP2_UFCS_0(f, t()) == 0);// Error: Argument `f` isn't "`constexpr`".
| ^~~~~~~~~~~~~~~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:790:38: note: expanded from macro 'CPP2_UFCS_0'
790 | #define CPP2_UFCS_0(FUNCNAME,PARAM1) \
| ^
main.cpp2:11:3: note: in instantiation of function template specialization 'g<int>' requested here
11 | g(0);
| ^
main.cpp2:7:17: note: function parameter 'f' with unknown value cannot be used in a constant expression
7 | static_assert(CPP2_UFCS_0(f, t()) == 0);// Error: Argument `f` isn't "`constexpr`".
| ^
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:791:2: note: expanded from macro 'CPP2_UFCS_0'
791 | [&] CPP2_LAMBDA_NO_DISCARD (auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
| ^
main.cpp2:5:20: note: declared here
5 | auto g(auto const& f) -> void{
| ^
1 error generated.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
JohelEGP commentedon Oct 29, 2023
My reading of https://eel.is/c++draft/expr.const#8
tells me that
g(0);will continue failingwhereas
g(std::identity());would be well-formed.#506's resolution for #550 adds quite some complexity to Cppfront.
The same can be done here to resolve this #788.
The alternative is to just embrace #550 and #788 as limitations of Cppfront,
and require users to not name such variables like the function in a UFCS call.
JohelEGP commentedon Oct 29, 2023
I have potential solutions in mind for this one.
But they also bring complexity to the code of Cppfront.
Maybe trial constant evaluation can be leveraged for a seamless user experience.
An alternative would be to disable UFCS
when in a constant expression (so Cppfront has to know about those)
and
fisn't part of the constant expression (determined by lexical name lookup).JohelEGP commentedon Dec 3, 2023
// g(std::identity()); // Might be OK since P2280R4 (unimplemented).Yes, it works: https://cpp2.godbolt.org/z/1vrf534qG.
JohelEGP commentedon Sep 30, 2024
(Now?)
g(0)also works with GCC (https://cpp2.godbolt.org/z/8v13hM44h).I'd expect Clang to work, by choosing the member, since that works, before even trying the object.
Maybe there's a Clang bug lurking,
or some constant expression quirk where Clang is strict and GCC is loose.
It's worth debugging the UFCS macro to see exactly what triggers Clang for further investigation.