// RUN:  %clang_cc1 -std=c++2a -verify %s
template<typename T, typename U> constexpr bool is_same_v = false;
template<typename T> constexpr bool is_same_v<T, T> = true;

template<typename T, unsigned size>
concept LargerThan = sizeof(T) > size;
// expected-note@-1 2{{because 'sizeof(char) > 1U' (1 > 1) evaluated to false}}
// expected-note@-2 {{because 'sizeof(int) > 10U' (4 > 10) evaluated to false}}
// expected-note@-3 {{because 'sizeof(int) > 4U' (4 > 4) evaluated to false}}

template<typename T>
concept Large = LargerThan<T, 1>;
// expected-note@-1 2{{because 'LargerThan<char, 1>' evaluated to false}}

namespace X {
  template<typename T, unsigned size>
  concept SmallerThan = sizeof(T) < size;
  template<typename T>
  concept Small = SmallerThan<T, 2>;
}

Large auto test1() { // expected-error{{deduced type 'char' does not satisfy 'Large'}}
  Large auto i = 'a';
  // expected-error@-1{{deduced type 'char' does not satisfy 'Large'}}
  Large auto j = 10;
  ::Large auto k = 10;
  LargerThan<1> auto l = 10;
  ::LargerThan<1> auto m = 10;
  LargerThan<10> auto n = 10;
  // expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<10>'}}
  X::Small auto o = 'x';
  X::SmallerThan<5> auto p = 1;
  return 'a';
}

::Large auto test2() { return 10; }
LargerThan<4> auto test3() { return 10; }
// expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<4>'}}
::LargerThan<2> auto test4() { return 10; }

Large auto test5() -> void;
// expected-error@-1{{function with trailing return type must specify return type 'auto', not 'Large auto'}}
auto test6() -> Large auto { return 1; }

X::Small auto test7() { return 'a'; }
X::SmallerThan<5> auto test8() { return 10; }

namespace PR48384 {
  int a = 0;
  int &b = a;
  template <class T> concept True = true;

  True auto c = a;
  static_assert(is_same_v<decltype(c), int>);

  True auto d = b;
  static_assert(is_same_v<decltype(d), int>);

  True decltype(auto) e = a;
  static_assert(is_same_v<decltype(e), int>);

  True decltype(auto) f = b;
  static_assert(is_same_v<decltype(f), int&>);

  True decltype(auto) g = (a);
  static_assert(is_same_v<decltype(g), int&>);

  True decltype(auto) h = (b);
  static_assert(is_same_v<decltype(h), int&>);
}

namespace PR48593 {
  template <class T, class U> concept a = true;
  a<B> auto c = 0; // expected-error{{use of undeclared identifier 'B'}}

  template<class> concept d = true;
  d<,> auto e = 0; // expected-error{{expected expression}}
}

namespace PR48617 {
  template <typename...> concept C = true;
  template <typename...> class A {};

  template <typename... Ts> C<Ts...> auto e(A<Ts...>) { return 0; }

  // FIXME: The error here does not make sense.
  template auto e<>(A<>);
  // expected-error@-1 {{explicit instantiation of 'e' does not refer to a function template}}
  // expected-note@-5  {{candidate template ignored: failed template argument deduction}}

  // FIXME: Should be able to instantiate this with no errors.
  template C<int> auto e<int>(A<int>);
  // expected-error@-1 {{explicit instantiation of 'e' does not refer to a function template}}
  // expected-note@-10 {{candidate template ignored: could not match 'C<int, Ts...> auto' against 'C<int> auto'}}
  
  template C<> auto e<>(A<>);

  template <typename... Ts> A<Ts...> c(Ts...);
  int f = e(c(1, 2));
}
