-
Notifications
You must be signed in to change notification settings - Fork 12.2k
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
Clang complains about concept depending on itself #62096
Comments
@llvm/issue-subscribers-clang-frontend |
@llvm/issue-subscribers-c-20 |
I think this should work but really @erichkeane should take a look |
I don't see any reason this shouldn't work, that looks right? And I admit the error message doesn't do a great job telling us what went wrong unfortunately. However, can anyone create a min-repro for this for me that doesn't include the include of the type trait? I wonder if the type trait is doing something goofy here. |
Actually, I got it down to: template <class OPERATOR>
concept Operator =
__is_nothrow_constructible(OPERATOR, OPERATOR&);
struct AnyOperator {
template <Operator OP>
explicit AnyOperator(OP op) noexcept {}
AnyOperator(const AnyOperator&) noexcept = default;
};
static_assert(Operator<AnyOperator>); Unless that builtin has something wacky happening, I don't see the recursion. The code that does just checks to see if we're still in the evaluation of something while being asked to evaluate the same constraint, but I'm not sure where that could have come from. |
I can only guess: If your remove the templated constructor it works. So I assume that:
|
AAh, so that builtin DOES cause this problem, and this is a legitimate diagnostic as far as I can tell. If I remove the diagnostic, we hit our template implementation limit.
So at the moment, I don't think this is a problem with the concepts stuff, but with that evaluation of the builtin. SO I'm not sure what I can do about it. @shafik : Perhaps its worth looking into that builtin/how GCC behaves with it? |
Yep! Looks like we simul-posted, thats exactly what is happening. The builtin is effectively doing |
I think the problem is that AnyOperator o = ...; // somehow initialize it
AnyOperator q(o); then the copy constructor should be selected (and not the template constructor). GCC and Clang (for Clang we must remove the concept constraint) both select the copy constructor, i.e. they are both correct. But |
Hmm... yes, I think thats it. We've somehow decided that our initialization here requires evaluating the template, even though there is already a non-template match. But I don't know our initialization code well enough to know the answer to that. Perhaps there is a missing DR here that we aren't implementing @hubert-reinterpretcast ? |
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as off-topic.
This comment was marked as off-topic.
Clang is doing the "directly conforming thing". The template is a candidate (https://wg21.link/over.match.ctor), and deduction (including checking of constraints; https://wg21.link/temp.deduct.general#5) happens before the rest of overload resolution. The only de jure reason that the copy constructor is the better candidate is that it is not a template (the template results in a viable candidate). GCC seems to "figure it out" by applying a special (ad hoc) rule against constructors that take their own class by value as the sole argument. It never bothered to check the constraints. https://godbolt.org/z/4nqETK5ba template <typename T>
struct Oops {
static_assert(sizeof(T) == 0); // GCC never sees this
static constexpr bool value = true;
};
template <class OPERATOR>
concept Operator = Oops<OPERATOR>::value;
struct AnyOperator {
template <Operator OP>
AnyOperator(OP op) noexcept {}
explicit AnyOperator(const AnyOperator&) noexcept = default;
};
void f(AnyOperator *ap) {
AnyOperator a = *ap;
} |
I don't see a defect here: The original reporter should simply have added a helper concept that checks that the constructor template argument is not |
The closest "rule" appears to be https://wg21.link/class.copy.ctor#5. However, the words:
technically mean that the definition is not produced (not the declaration, despite references to "signature"). There is also nothing in those words that indicate where in the deduction/substitution/constraint checking/etc. process this kicks in. |
It appears that Clang also has some version of the "rule". https://godbolt.org/z/hT4nfvxnW struct AnyOperator {
template <typename OP>
AnyOperator(OP op, int = 0) noexcept {} // Clang rejects this candidate for the copy initialization of `op`
explicit AnyOperator(const AnyOperator&) noexcept {}
};
void f(AnyOperator *ap) {
AnyOperator a(*ap, 0);
} |
Yours is a different issue @ckwastra. The originally-reported issue hinges on when a constructor template candidate should be rejected. Your issue is a bug in Clang's name lookup for dependent operator function calls using the overloaded operator syntax. namespace Q {
struct A {};
}
template <class T>
int operator+(T, char (*)[0 ?
T{} + static_cast<char (*)[1]>(0) :
1]); // Not recursive: `operator+` only available to unqualified name lookup following the end of the declarators
int f() {
return Q::A{} + static_cast<char (*)[1]>(0);
} |
|
In addition to the question of when the "substitution produces a template <typename T>
struct Oops {
static_assert(sizeof(T) == 0);
static constexpr bool value = true;
};
template <class OPERATOR>
concept Operator = Oops<OPERATOR>::value;
template <Operator OP> void f(OP op);
void f(int);
// Clang rejects, GCC accepts
void g(int n) { f(n); }
// Both reject
void h(short n) { f(n); } |
Version of Clang
Steps to reproduce the problem
Try to compile the following program with
clang++ main.cpp -std=c++20 -ftemplate-backtrace-limit=0
:It produces the following output (see also Godbolt):
Correct behavior
Clang should accept the code. As far as I know the code is valid. It compiles fine with MSVC and GCC.
The text was updated successfully, but these errors were encountered: