Skip to content

[clang] Satisfaction of constraint depends on itself for type with single-argument constructor #143918

Open
@davidstone

Description

@davidstone

The following translation unit

template<typename LHS, typename RHS>
concept c = requires(LHS lhs, RHS rhs) { f(lhs, rhs); };

struct unconstrained {
	template<typename T>
	friend void f(unconstrained, T);
};

struct constrained {
	explicit constrained(int = 0);

	template<typename T> requires c<int, T>
	friend void f(constrained, T);
};

void g() {
	f(unconstrained(), constrained());
}

is rejected by clang with

<source>:12:32: error: satisfaction of constraint 'c<int, T>' depends on itself
   12 |         template<typename T> requires c<int, T>
      |                                       ^~~~~~~~~
<source>:12:32: note: while substituting template arguments into constraint expression here
   12 |         template<typename T> requires c<int, T>
      |                                       ^~~~~~~~~
<source>:2:42: note: while checking constraint satisfaction for template 'f<constrained>' required here
    2 | concept c = requires(LHS lhs, RHS rhs) { f(lhs, rhs); };
      |                                          ^
<source>:2:42: note: while substituting deduced template arguments into function template 'f' [with T = constrained]
<source>:2:42: note: in instantiation of requirement here
    2 | concept c = requires(LHS lhs, RHS rhs) { f(lhs, rhs); };
      |                                          ^~~~~~~~~~~
<source>:2:13: note: while substituting template arguments into constraint expression here
    2 | concept c = requires(LHS lhs, RHS rhs) { f(lhs, rhs); };
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:12:32: note: while checking the satisfaction of concept 'c<int, constrained>' requested here
   12 |         template<typename T> requires c<int, T>
      |                                       ^~~~~~~~~
<source>:12:32: note: while substituting template arguments into constraint expression here
   12 |         template<typename T> requires c<int, T>
      |                                       ^~~~~~~~~
<source>:17:2: note: while checking constraint satisfaction for template 'f<constrained>' required here
   17 |         f(unconstrained(), constrained());
      |         ^
<source>:17:2: note: while substituting deduced template arguments into function template 'f' [with T = constrained]
<source>:17:2: error: no matching function for call to 'f'
   17 |         f(unconstrained(), constrained());
      |         ^
<source>:6:14: note: candidate function [with T = constrained]
    6 |         friend void f(unconstrained, T);
      |                     ^
<source>:13:14: note: candidate template ignored: constraints not satisfied [with T = constrained]
   13 |         friend void f(constrained, T);
      |                     ^
2 errors generated.
Compiler returned: 1

See it live: https://godbolt.org/z/sn1bbq6Kz

Removing the constructor on line 10 removes the error message.

It seems that clang is instantiating the friend function template f from line 12 with constrained as T, and then before realizing that unconstrained cannot convert to constrained it tries to evaluate the concept which then attempts to instantiate this same function template.

The error message also goes on to say that there is no matching function for call to f, even though it lists the function template on line 5 (which is valid and is expected to be called) as a candidate.

This code is accepted in clang 20.1.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"conceptsC++20 concepts

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions