Files
clang-p2996/clang/test/SemaTemplate/temp_arg_template.cpp
Matheus Izvekov e29c085812 [clang] disallow narrowing when matching template template parameters (#124313)
This fixes the core issue described in P3579, following the design
intent of P0522 to not introduce any new cases where a template template
parameter match is allowed for a template which is not valid for all
possible uses.

With this patch, narrowing conversions are disallowed for TTP matching.

This reuses the existing machinery for diagnosing narrowing in a
converted constant expression.
Since P0522 is a DR and we apply it all the way back to C++98, this
brings that machinery to use in older standards, in this very narrow
scope of TTP matching.

This still doesn't solve the ambiguity when partial ordering NTTPs of
different integral types, this is blocked by a different bug which will
be fixed in a subsequent patch (but the test cases are added).
2025-01-28 15:51:17 -03:00

159 lines
5.1 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx17 %std_cxx98-14 %s
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 -std=c++17 %s
template<template<typename T> class X> struct A; // #A
// expected-note@-1 2{{previous template template parameter is here}}
template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}}
template<template<int I> class X> struct C;
// expected-error@-1 {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}}
// expected-note@-2 {{previous template template parameter is here}}
template<class> struct X; // expected-note {{template is declared here}}
template<int N> struct Y; // expected-note {{template parameter is declared here}}
template<long N> struct Ylong;
template<const int &N> struct Yref; // expected-note {{template parameter is declared here}}
namespace N {
template<class> struct Z;
}
template<class, class> struct TooMany; // expected-note{{template is declared here}}
A<X> *a1;
A<N::Z> *a2;
A< ::N::Z> *a3;
A<Y> *a4; // expected-error@#A {{template argument for non-type template parameter must be an expression}}
// expected-note@-1 {{different template parameters}}
A<TooMany> *a5; // expected-error {{too few template arguments for class template 'TooMany'}}
// expected-note@-1 {{different template parameters}}
B<X> *a6; // expected-error {{too many template arguments for class template 'X'}}
// expected-note@-1 {{different template parameters}}
C<Y> *a7;
C<Ylong> *a8;
C<Yref> *a9; // expected-note {{different template parameters}}
template<typename T> void f(int);
A<f> *a9; // expected-error{{must be a class template}}
// Evil digraph '<:' is parsed as '[', expect error.
A<::N::Z> *a10;
#if __cplusplus <= 199711L
// expected-error@-2 {{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
#endif
// Do not do a digraph correction here.
A<: :N::Z> *a11; // expected-error{{expected expression}} \
precxx17-error{{a type specifier is required for all declarations}} \
cxx17-error{{expected unqualified-id}}
// PR7807
namespace N {
template <typename, typename = int>
struct X
{ };
template <typename ,int>
struct Y
{ X<int> const_ref(); };
template <template<typename,int> class TT, typename T, int N>
int operator<<(int, TT<T, N> a) { // expected-note{{candidate template ignored}}
0 << a.const_ref(); // expected-error{{invalid operands to binary expression ('int' and 'X<int>')}}
}
void f0( Y<int,1> y){ 1 << y; } // expected-note{{in instantiation of function template specialization 'N::operator<<<N::Y, int, 1>' requested here}}
}
// PR12179
template <typename Primitive, template <Primitive...> class F>
#if __cplusplus <= 199711L
// expected-warning@-2 {{variadic templates are a C++11 extension}}
#endif
struct unbox_args {
typedef typename Primitive::template call<F> x;
};
template <template <typename> class... Templates>
#if __cplusplus <= 199711L
// expected-warning@-2 {{variadic templates are a C++11 extension}}
#endif
struct template_tuple {
#if __cplusplus >= 201103L
static constexpr int N = sizeof...(Templates);
#endif
};
template <typename T>
struct identity {};
template <template <typename> class... Templates>
#if __cplusplus <= 199711L
// expected-warning@-2 {{variadic templates are a C++11 extension}}
#endif
template_tuple<Templates...> f7() {}
#if __cplusplus >= 201103L
struct S : public template_tuple<identity, identity> {
static_assert(N == 2, "Number of template arguments incorrect");
};
#endif
void foo() {
f7<identity>();
}
namespace CheckDependentNonTypeParamTypes {
template<template<typename T, typename U, T v> class X> struct A {
// expected-note@-1 {{previous template template parameter is here}}
void f() {
X<int, void*, 3> x;
}
void g() {
X<int, long, 3> x;
}
void h() {
// FIXME: If we accept A<B> at all, it's not obvious what should happen
// here. While parsing the template, we form
// X<unsigned char, int, (unsigned char)1234>
// but in the final instantiation do we get
// B<unsigned char, int, (int)1234>
// or
// B<unsigned char, int, (int)(unsigned char)1234>
// ?
X<unsigned char, int, 1234> x;
int check[x.value == 1234 ? 1 : -1];
}
};
template<typename T, typename U, U v> struct B {
// expected-error@-1 {{conflicting deduction 'U' against 'T' for parameter}}
static const U value = v;
};
// FIXME: This should probably be rejected, but the rules are at best unclear.
A<B> ab; // expected-note {{different template parameters}}
void use() {
ab.f();
ab.g();
ab.h();
}
}
namespace PR32185 {
template<template<typename T, T> class U> struct A {};
template<template<typename T, T> class U> struct B : A<U> {};
}
namespace PR10147 {
template<typename T> struct A {};
template<typename T = int> struct A;
template<template<typename...> class A> void f(A<int>*) { A<> a; } // expected-warning 0-1{{extension}}
void g() { f((A<>*)0); }
}