llvm/clang/test/CXX/temp/temp.res/p4.cpp

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

struct X {
  using type = int;
  static constexpr int value = 1;
  class tclass {};
};

template <typename T>
void f() {
  // it is a qualified name in a type-id-only context (see below), or
  // [its smallest enclosing [/new/defining/]-type-id is]:
  // - a new-type-id
  auto *Ptr = new T::type();
  // - a defining-type-id
  class T::tclass Empty1;
  T::tclass Empty2; // expected-error{{missing 'typename'}}
  // - a trailing-return-type
  auto f()->T::type;
  // - default argument of a type-parameter of a template [see below]

  // - type-id of a
  // static_cast,
  auto StaticCast = static_cast<T::type>(1.2);
  // const_cast,
  const auto *ConstCast = const_cast<const T::type *>(Ptr);
  // reinterpret_cast,
  int ReinterpretCast = reinterpret_cast<T::type>(4);
  // dynamic_cast
  struct B {
    virtual ~B() = default;
  };
  struct D : T::tclass {};
  auto *Base = dynamic_cast<T::tclass *>(new B);

  T::type Invalid; // expected-error{{missing 'typename'}}
}

template void f<X>();

// As default argument.
template <typename T, typename = T::type>
struct DefaultArg {};

template struct DefaultArg<X>;

// it is a decl-specifier of the decl-specifier-seq of a
// - simple-declaration or a function-definition in namespace scope
template <typename T>
T::type VarTemp = 1;

template int VarTemp<X>;

template <typename T>
T::type FuncDef() { return 1; }

template int FuncDef<X>();

template <typename T>
T::type funcDecl();

template <typename T>
void FuncParam(T::type); // ok, but variable template
// expected-error@-1{{variable has incomplete type 'void'}}

template <typename T>
void FuncParam2(const T::type, int); // expected-error{{missing 'typename'}}

template <typename T>
struct MemberDecl {
  // member-declaration,
  T::type Member;

  // parameter-declaration in a member-declaration, unless that
  // parameter-declaration appears in a default argument
  void NoDefault(T::type);
  void Default(int A = T::value);
};

template struct MemberDecl<X>;

// parameter-declaration in a declarator of a function or function template
// declaration where the declarator-id is qualified, unless that
// parameter-declaration appears in a default argument,
struct QualifiedFunc {
  template <typename T>
  void foo(typename T::type);
  template <typename T>
  void bar(T::type);
};

template <typename T>
void QualifiedFunc::foo(T::type) {}
template <typename T>
void QualifiedFunc::bar(typename T::type) {}

template <typename T>
void g() {
  // parameter-declaration in a lambda-declarator, unless that
  // parameter-declaration appears in a default argument, or
  auto Lambda1 = [](T::type) {};
  auto Lambda2 = [](int A = T::value) {};
}

template void g<X>();

// parameter-declaration of a (non-type) template-parameter.
template <typename T, T::type>
void NonTypeArg() {}

template void NonTypeArg<X, 0>();

template <typename T>
void f(T::type) {} // expected-error {{missing 'typename'}}

namespace N {
  template <typename T>
  int f(typename T::type);
  template <typename T>
  extern int Var;
}

template <typename T>
int N::f(T::type); // ok, function
template <typename T>
int N::Var(T::value); // ok, variable

int h() {
  return N::f<X>(10) + N::Var<X>;
}

namespace NN {
  inline namespace A { template <typename T> int f(typename T::type); } // expected-note{{previous definition is here}}
  inline namespace B { template <typename T> int f(T::type); }
}

template <typename T>
int NN::f(T::type); // expected-error{{redefinition of 'f' as different kind of symbol}}

template <auto V>
struct videntity {
  static constexpr auto value = V;
};

template <typename T,
    bool = T::value,
    bool = bool(T::value),
    bool = videntity<bool(T::value)>::value>
void f(int = T::value) {}

template <typename> int test() = delete;
template <auto> int test();

template <typename T>
int Test = test<int(T::value)>();
template int Test<X>;

template<typename T> struct A {
  enum E : T::type {}; // expected-error{{missing 'typename'}}
  operator T::type() {} // expected-error{{missing 'typename'}}
  void f() { this->operator T::type(); } // expected-error{{missing 'typename'}}
};

template<typename T>
struct C {
  C(T::type); // implicit typename context
  friend C (T::fn)(); // not implicit typename context, declarator-id of friend declaration
  C(T::type::*x)[3]; // not implicit typename context, pointer-to-member type
};

template <typename T>
C<T>::C(T::type) {}

namespace GH63119 {
struct X {
    X(int);
    X(auto);
    void f(int);
};
template<typename T> struct S {
  friend X::X(T::type);
  friend X::X(T::type = (int)(void(*)(typename T::type))(nullptr)); // expected-error {{friend declaration specifying a default argument must be a definition}}
  friend X::X(T::type = (int)(void(*)(T::type))(nullptr)); // expected-error {{friend declaration specifying a default argument must be a definition}} \
                                                           // expected-error {{expected expression}}
  friend void X::f(T::type);
};
}