| // 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); |
| }; |
| } |