llvm/clang/test/SemaTemplate/concepts-recovery-expr.cpp

// RUN: %clang_cc1 -std=c++20 -verify %s

// expected-error@+1{{use of undeclared identifier 'b'}}
constexpr bool CausesRecoveryExpr = b;

template<typename T>
concept ReferencesCRE = CausesRecoveryExpr;

template<typename T> requires CausesRecoveryExpr // #NVC1REQ
void NoViableCands1(){} // #NVC1

template<typename T> requires ReferencesCRE<T> // #NVC2REQ
void NoViableCands2(){} // #NVC2

template<ReferencesCRE T> // #NVC3REQ
void NoViableCands3(){} // #NVC3

void NVCUse() {
  NoViableCands1<int>();
  // expected-error@-1 {{no matching function for call to 'NoViableCands1'}}
  // expected-note@#NVC1{{candidate template ignored: constraints not satisfied}}
  // expected-note@#NVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}

  NoViableCands2<int>();
  // expected-error@-1 {{no matching function for call to 'NoViableCands2'}}
  // expected-note@#NVC2{{candidate template ignored: constraints not satisfied}}
  // expected-note@#NVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  NoViableCands3<int>();
  // expected-error@-1 {{no matching function for call to 'NoViableCands3'}}
  // expected-note@#NVC3{{candidate template ignored: constraints not satisfied}}
  // expected-note@#NVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}

template<typename T> requires CausesRecoveryExpr // #OVC1REQ
void OtherViableCands1(){} // #OVC1

template<typename T>
void OtherViableCands1(){} // #OVC1_ALT

template<typename T> requires ReferencesCRE<T> // #OVC2REQ
void OtherViableCands2(){} // #OVC2

template<typename T>
void OtherViableCands2(){} // #OVC2_ALT

template<ReferencesCRE T> // #OVC3REQ
void OtherViableCands3(){} // #OVC3
template<typename T>
void OtherViableCands3(){} // #OVC3_ALT

void OVCUse() {
  OtherViableCands1<int>();
  // expected-error@-1 {{no matching function for call to 'OtherViableCands1'}}
  // expected-note@#OVC1_ALT {{candidate function}}
  // expected-note@#OVC1 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  OtherViableCands2<int>();
  // expected-error@-1 {{no matching function for call to 'OtherViableCands2'}}
  // expected-note@#OVC2_ALT {{candidate function}}
  // expected-note@#OVC2 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  OtherViableCands3<int>();
  // expected-error@-1 {{no matching function for call to 'OtherViableCands3'}}
  // expected-note@#OVC3_ALT {{candidate function}}
  // expected-note@#OVC3 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}

template<typename T> requires CausesRecoveryExpr // #OBNVC1REQ
void OtherBadNoViableCands1(){} // #OBNVC1

template<typename T> requires false // #OBNVC1REQ_ALT
void OtherBadNoViableCands1(){} // #OBNVC1_ALT

template<typename T> requires ReferencesCRE<T> // #OBNVC2REQ
void OtherBadNoViableCands2(){} // #OBNVC2

template<typename T> requires false// #OBNVC2REQ_ALT
void OtherBadNoViableCands2(){} // #OBNVC2_ALT

template<ReferencesCRE T> // #OBNVC3REQ
void OtherBadNoViableCands3(){} // #OBNVC3
template<typename T> requires false // #OBNVC3REQ_ALT
void OtherBadNoViableCands3(){} // #OBNVC3_ALT

void OBNVCUse() {
  OtherBadNoViableCands1<int>();
  // expected-error@-1 {{no matching function for call to 'OtherBadNoViableCands1'}}
  // expected-note@#OBNVC1_ALT {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OBNVC1REQ_ALT {{because 'false' evaluated to false}}
  // expected-note@#OBNVC1 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OBNVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  OtherBadNoViableCands2<int>();
  // expected-error@-1 {{no matching function for call to 'OtherBadNoViableCands2'}}
  // expected-note@#OBNVC2_ALT {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OBNVC2REQ_ALT {{because 'false' evaluated to false}}
  // expected-note@#OBNVC2 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OBNVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  OtherBadNoViableCands3<int>();
  // expected-error@-1 {{no matching function for call to 'OtherBadNoViableCands3'}}
  // expected-note@#OBNVC3_ALT {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OBNVC3REQ_ALT {{because 'false' evaluated to false}}
  // expected-note@#OBNVC3 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#OBNVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}


// Same tests with member functions.
struct OVC {
template<typename T> requires CausesRecoveryExpr // #MEMOVC1REQ
void OtherViableCands1(){} // #MEMOVC1

template<typename T>
void OtherViableCands1(){} // #MEMOVC1_ALT

template<typename T> requires ReferencesCRE<T> // #MEMOVC2REQ
void OtherViableCands2(){} // #MEMOVC2

template<typename T>
void OtherViableCands2(){} // #MEMOVC2_ALT

template<ReferencesCRE T> // #MEMOVC3REQ
void OtherViableCands3(){} // #MEMOVC3
template<typename T>
void OtherViableCands3(){} // #MEMOVC3_ALT
};

void MemOVCUse() {
  OVC S;
  S.OtherViableCands1<int>();
  // expected-error@-1 {{no matching member function for call to 'OtherViableCands1'}}
  // expected-note@#MEMOVC1_ALT {{candidate function}}
  // expected-note@#MEMOVC1 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#MEMOVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  S.OtherViableCands2<int>();
  // expected-error@-1 {{no matching member function for call to 'OtherViableCands2'}}
  // expected-note@#MEMOVC2_ALT {{candidate function}}
  // expected-note@#MEMOVC2 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#MEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  S.OtherViableCands3<int>();
  // expected-error@-1 {{no matching member function for call to 'OtherViableCands3'}}
  // expected-note@#MEMOVC3_ALT {{candidate function}}
  // expected-note@#MEMOVC3 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#MEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}

struct StaticOVC {
template<typename T> requires CausesRecoveryExpr // #SMEMOVC1REQ
static void OtherViableCands1(){} // #SMEMOVC1

template<typename T>
static void OtherViableCands1(){} // #SMEMOVC1_ALT

template<typename T> requires ReferencesCRE<T> // #SMEMOVC2REQ
static void OtherViableCands2(){} // #SMEMOVC2

template<typename T>
static void OtherViableCands2(){} // #SMEMOVC2_ALT

template<ReferencesCRE T> // #SMEMOVC3REQ
static void OtherViableCands3(){} // #SMEMOVC3
template<typename T>
static void OtherViableCands3(){} // #SMEMOVC3_ALT
};

void StaticMemOVCUse() {
  StaticOVC::OtherViableCands1<int>();
  // expected-error@-1 {{no matching function for call to 'OtherViableCands1'}}
  // expected-note@#SMEMOVC1_ALT {{candidate function}}
  // expected-note@#SMEMOVC1 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#SMEMOVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  StaticOVC::OtherViableCands2<int>();
  // expected-error@-1 {{no matching function for call to 'OtherViableCands2'}}
  // expected-note@#SMEMOVC2_ALT {{candidate function}}
  // expected-note@#SMEMOVC2 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#SMEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
  StaticOVC::OtherViableCands3<int>();
  // expected-error@-1 {{no matching function for call to 'OtherViableCands3'}}
  // expected-note@#SMEMOVC3_ALT {{candidate function}}
  // expected-note@#SMEMOVC3 {{candidate template ignored: constraints not satisfied}}
  // expected-note@#SMEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}

namespace GH58548 {

template <class, class> struct formatter; // #primary-template
template <class, class> struct basic_format_context {};

template <typename CharType>
concept has_format_function =
    format(basic_format_context<CharType, CharType>());

template <typename ValueType, typename CharType>
  requires has_format_function<CharType>
struct formatter<ValueType, CharType> {
  template <typename OutputIt>
  CharType format(basic_format_context<OutputIt, CharType>);
};

template <class Ctx> int handle_replacement_field(Ctx arg) {
  formatter<decltype(arg), int> ctx; // expected-error {{implicit instantiation of undefined template}}
  return 0;
}

int x = handle_replacement_field(0);
// expected-note@-1 {{template specialization 'GH58548::handle_replacement_field<int>' requested here}}
// expected-note@#primary-template {{is declared here}}

} // GH58548