binutils-gdb/gdb/testsuite/gdb.cp/templates.cc
Keith Seitz 64a9760601 Support template lookups in strncmp_iw_with_mode
This patch adds support for wild template parameter list matches, similar
to how ABI tags or function overloads are now handled.

With this patch, users will be able to "gloss over" the details of matching
template parameter lists.  This is accomplished by adding (yet more) logic
to strncmp_iw_with_mode to skip parameter lists if none is explicitly given
by the user.

Here's a simple example using gdb.linespec/cpls-ops.exp:

Before
------
(gdb) ptype test_op_call
type = struct test_op_call {
  public:
    void operator()(void);
    void operator()(int);
    void operator()(long);
    void operator()<int>(int *);
}
(gdb) b test_op_call::operator()
Breakpoint 1 at 0x400583: test_op_call::operator(). (3 locations)
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>
1.1                         y     0x400583 in test_op_call::operator()(int)
                                                   at cpls-ops.cc:43
1.2                         y     0x40058e in test_op_call::operator()()
                                                   at cpls-ops.cc:47
1.3                         y     0x40059e in test_op_call::operator()(long)
                                                   at cpls-ops.cc:51

The breakpoint at test_op_call::operator()<int> was never set.

After
-----
(gdb) b test_op_call::operator()
Breakpoint 1 at 0x400583: test_op_call::operator(). (4 locations)
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>
1.1                         y     0x400583 in test_op_call::operator()(int)
                                                   at cpls-ops.cc:43
1.2                         y     0x40058e in test_op_call::operator()()
                                                   at cpls-ops.cc:47
1.3                         y     0x40059e in test_op_call::operator()(long)
                                                   at cpls-ops.cc:51
1.4                         y     0x4008d0 in test_op_call::operator()<int>(int*)
                                                   at cpls-ops.cc:57

Similar to how scope lookups work, passing "-qualified" to the break command
will cause a literal lookup of the symbol.  In the example immediately above,
this will cause GDB to only find the three non-template functions.
2022-02-24 16:42:22 -08:00

867 lines
18 KiB
C++

/* This test code is from Wendell Baker (wbaker@comet.berkeley.edu) */
#include <stddef.h>
int a_i;
char a_c;
double a_d;
typedef void *Pix;
int
f(int i)
{ return 0; }
int
f(int i, char c)
{ return 0; }
int
f(int i, char c, double d)
{ return 0; }
int
f(int i, char c, double d, char *cs)
{ return 0; }
int
f(int i, char c, double d, char *cs, void (*fig)(int, char))
{ return 0; }
int
f(int i, char c, double d, char *cs, void (*fig)(char, int))
{ return 0; }
class R {
public:
int i;
};
class S {
public:
int i;
};
class T {
public:
int i;
};
char g(char, const char, volatile char)
{ return 'c'; }
char g(R, char&, const char&, volatile char&)
{ return 'c'; }
char g(char*, const char*, volatile char*)
{ return 'c'; }
char g(S, char*&, const char*&, volatile char*&)
{ return 'c'; }
signed char g(T,signed char, const signed char, volatile signed char)
{ return 'c'; }
signed char g(T, R, signed char&, const signed char&, volatile signed char&)
{ return 'c'; }
signed char g(T, signed char*, const signed char*, volatile signed char*)
{ return 'c'; }
signed char g(T, S, signed char*&, const signed char*&, volatile signed char*&)
{ return 'c'; }
unsigned char g(unsigned char, const unsigned char, volatile unsigned char)
{ return 'c'; }
unsigned char g(R, unsigned char&, const unsigned char&, volatile unsigned char&)
{ return 'c'; }
unsigned char g(unsigned char*, const unsigned char*, volatile unsigned char*)
{ return 'c'; }
unsigned char g(S, unsigned char*&, const unsigned char*&, volatile unsigned char*&)
{ return 'c'; }
short g(short, const short, volatile short)
{ return 0; }
short g(R, short&, const short&, volatile short&)
{ return 0; }
short g(short*, const short*, volatile short*)
{ return 0; }
short g(S, short*&, const short*&, volatile short*&)
{ return 0; }
signed short g(T, signed short, const signed short, volatile signed short)
{ return 0; }
signed short g(T, R, signed short&, const signed short&, volatile signed short&)
{ return 0; }
signed short g(T, signed short*, const signed short*, volatile signed short*)
{ return 0; }
signed short g(T, S, double, signed short*&, const signed short*&, volatile signed short*&)
{ return 0; }
unsigned short g(unsigned short, const unsigned short, volatile unsigned short)
{ return 0; }
unsigned short g(R, unsigned short&, const unsigned short&, volatile unsigned short&)
{ return 0; }
unsigned short g(unsigned short*, const unsigned short*, volatile unsigned short*)
{ return 0; }
unsigned short g(S, unsigned short*&, const unsigned short*&, volatile unsigned short*&)
{ return 0; }
int g(int, const int, volatile int)
{ return 0; }
int g(R, int&, const int&, volatile int&)
{ return 0; }
int g(int*, const int*, volatile int*)
{ return 0; }
int g(S, int*&, const int*&, volatile int*&)
{ return 0; }
signed int g(T, signed int, const signed int, volatile signed int)
{ return 0; }
signed int g(T, R, signed int&, const signed int&, volatile signed int&)
{ return 0; }
signed int g(T, signed int*, const signed int*, volatile signed int*)
{ return 0; }
signed int g(T, S, signed int*&, const signed int*&, volatile signed int*&)
{ return 0; }
unsigned int g(unsigned int, const unsigned int, volatile unsigned int)
{ return 0; }
unsigned int g(R, unsigned int&, const unsigned int&, volatile unsigned int&)
{ return 0; }
unsigned int g(unsigned int*, const unsigned int*, volatile unsigned int*)
{ return 0; }
unsigned int g(S, unsigned int*&, const unsigned int*&, volatile unsigned int*&)
{ return 0; }
long g(long, const long, volatile long)
{ return 0; }
long g(R, long&, const long&, volatile long&)
{ return 0; }
long g(long*, const long*, volatile long*)
{ return 0; }
long g(S, long*&, const long*&, volatile long*&)
{ return 0; }
signed long g(T, signed long, const signed long, volatile signed long)
{ return 0; }
signed long g(T, R, signed long&, const signed long&, volatile signed long&)
{ return 0; }
signed long g(T, signed long*, const signed long*, volatile signed long*)
{ return 0; }
signed long g(T, S, signed long*&, const signed long*&, volatile signed long*&)
{ return 0; }
unsigned long g(unsigned long, const unsigned long, volatile unsigned long)
{ return 0; }
unsigned long g(S, unsigned long&, const unsigned long&, volatile unsigned long&)
{ return 0; }
unsigned long g(unsigned long*, const unsigned long*, volatile unsigned long*)
{ return 0; }
unsigned long g(S, unsigned long*&, const unsigned long*&, volatile unsigned long*&)
{ return 0; }
#ifdef __GNUC__
long long g(long long, const long long, volatile long long)
{ return 0; }
long long g(S, long long&, const long long&, volatile long long&)
{ return 0; }
long long g(long long*, const long long*, volatile long long*)
{ return 0; }
long long g(R, long long*&, const long long*&, volatile long long*&)
{ return 0; }
signed long long g(T, signed long long, const signed long long, volatile signed long long)
{ return 0; }
signed long long g(T, R, signed long long&, const signed long long&, volatile signed long long&)
{ return 0; }
signed long long g(T, signed long long*, const signed long long*, volatile signed long long*)
{ return 0; }
signed long long g(T, S, signed long long*&, const signed long long*&, volatile signed long long*&)
{ return 0; }
unsigned long long g(unsigned long long, const unsigned long long, volatile unsigned long long)
{ return 0; }
unsigned long long g(R, unsigned long long*, const unsigned long long*, volatile unsigned long long*)
{ return 0; }
unsigned long long g(unsigned long long&, const unsigned long long&, volatile unsigned long long&)
{ return 0; }
unsigned long long g(S, unsigned long long*&, const unsigned long long*&, volatile unsigned long long*&)
{ return 0; }
#endif
float g(float, const float, volatile float)
{ return 0; }
float g(char, float&, const float&, volatile float&)
{ return 0; }
float g(float*, const float*, volatile float*)
{ return 0; }
float g(char, float*&, const float*&, volatile float*&)
{ return 0; }
double g(double, const double, volatile double)
{ return 0; }
double g(char, double&, const double&, volatile double&)
{ return 0; }
double g(double*, const double*, volatile double*)
{ return 0; }
double g(char, double*&, const double*&, volatile double*&)
{ return 0; }
#ifdef __GNUC__
long double g(long double, const long double, volatile long double)
{ return 0; }
long double g(char, long double&, const long double&, volatile long double&)
{ return 0; }
long double g(long double*, const long double*, volatile long double*)
{ return 0; }
long double g(char, long double*&, const long double*&, volatile long double*&)
{ return 0; }
#endif
class c {
public:
c(int) {};
int i;
};
class c g(c, const c, volatile c)
{ return 0; }
c g(char, c&, const c&, volatile c&)
{ return 0; }
c g(c*, const c*, volatile c*)
{ return 0; }
c g(char, c*&, const c*&, volatile c*&)
{ return 0; }
/*
void h(char = 'a')
{ }
void h(char, signed char = 'a')
{ }
void h(unsigned char = 'a')
{ }
*/
/*
void h(char = (char)'a')
{ }
void h(char, signed char = (signed char)'a')
{ }
void h(unsigned char = (unsigned char)'a')
{ }
void h(short = (short)43)
{ }
void h(char, signed short = (signed short)43)
{ }
void h(unsigned short = (unsigned short)43)
{ }
void h(int = (int)43)
{ }
void h(char, signed int = (signed int)43)
{ }
void h(unsigned int = (unsigned int)43)
{ }
void h(long = (long)43)
{ }
void h(char, signed long = (signed long)43)
{ }
void h(unsigned long = (unsigned long)43)
{ }
#ifdef __GNUC__
void h(long long = 43)
{ }
void h(char, signed long long = 43)
{ }
void h(unsigned long long = 43)
{ }
#endif
void h(float = 4.3e-10)
{ }
void h(double = 4.3)
{ }
#ifdef __GNUC__
void h(long double = 4.33e33)
{ }
#endif
*/
/* An unneeded printf() definition - actually, just a stub - used to occupy
this space. It has been removed and replaced with this comment which
exists to occupy some lines so that templates.exp won't need adjustment. */
class T1 {
public:
static void* operator new(size_t) throw ();
static void operator delete(void *pointer);
void operator=(const T1&);
T1& operator=(int);
int operator==(int) const;
int operator==(const T1&) const;
int operator!=(int) const;
int operator!=(const T1&) const;
int operator<=(int) const;
int operator<=(const T1&) const;
int operator<(int) const;
int operator<(const T1&) const;
int operator>=(int) const;
int operator>=(const T1&) const;
int operator>(int) const;
int operator>(const T1&) const;
void operator+(int) const;
T1& operator+(const T1&) const;
void operator+=(int) const;
T1& operator+=(const T1&) const;
T1& operator++() const;
void operator-(int) const;
T1& operator-(const T1&) const;
void operator-=(int) const;
T1& operator-=(const T1&) const;
T1& operator--() const;
void operator*(int) const;
T1& operator*(const T1&) const;
void operator*=(int) const;
T1& operator*=(const T1&) const;
void operator/(int) const;
T1& operator/(const T1&) const;
void operator/=(int) const;
T1& operator/=(const T1&) const;
void operator%(int) const;
T1& operator%(const T1&) const;
void operator%=(int) const;
T1& operator%=(const T1&) const;
void operator&&(int) const;
T1& operator&&(const T1&) const;
void operator||(int) const;
T1& operator||(const T1&) const;
void operator&(int) const;
T1& operator&(const T1&) const;
void operator&=(int) const;
T1& operator&=(const T1&) const;
void operator|(int) const;
T1& operator|(const T1&) const;
void operator|=(int) const;
T1& operator|=(const T1&) const;
void operator^(int) const;
T1& operator^(const T1&) const;
void operator^=(int) const;
T1& operator^=(const T1&) const;
T1& operator!() const;
T1& operator~() const;
};
void*
T1::operator new(size_t) throw ()
{ return 0; }
void
T1::operator delete(void *pointer)
{ }
class T2 {
public:
T2(int i): integer(i)
{ }
int integer;
};
int operator==(const T2&, const T2&)
{ return 0; }
int operator==(const T2&, char)
{ return 0; }
int operator!=(const T2&, const T2&)
{ return 0; }
int operator!=(const T2&, char)
{ return 0; }
int operator<=(const T2&, const T2&)
{ return 0; }
int operator<=(const T2&, char)
{ return 0; }
int operator<(const T2&, const T2&)
{ return 0; }
int operator<(const T2&, char)
{ return 0; }
int operator>=(const T2&, const T2&)
{ return 0; }
int operator>=(const T2&, char)
{ return 0; }
int operator>(const T2&, const T2&)
{ return 0; }
int operator>(const T2&, char)
{ return 0; }
T2 operator+(const T2 t, int i)
{ return t.integer + i; }
T2 operator+(const T2 a, const T2& b)
{ return a.integer + b.integer; }
T2& operator+=(T2& t, int i)
{ t.integer += i; return t; }
T2& operator+=(T2& a, const T2& b)
{ a.integer += b.integer; return a; }
T2 operator-(const T2 t, int i)
{ return t.integer - i; }
T2 operator-(const T2 a, const T2& b)
{ return a.integer - b.integer; }
T2& operator-=(T2& t, int i)
{ t.integer -= i; return t; }
T2& operator-=(T2& a, const T2& b)
{ a.integer -= b.integer; return a; }
T2 operator*(const T2 t, int i)
{ return t.integer * i; }
T2 operator*(const T2 a, const T2& b)
{ return a.integer * b.integer; }
T2& operator*=(T2& t, int i)
{ t.integer *= i; return t; }
T2& operator*=(T2& a, const T2& b)
{ a.integer *= b.integer; return a; }
T2 operator/(const T2 t, int i)
{ return t.integer / i; }
T2 operator/(const T2 a, const T2& b)
{ return a.integer / b.integer; }
T2& operator/=(T2& t, int i)
{ t.integer /= i; return t; }
T2& operator/=(T2& a, const T2& b)
{ a.integer /= b.integer; return a; }
T2 operator%(const T2 t, int i)
{ return t.integer % i; }
T2 operator%(const T2 a, const T2& b)
{ return a.integer % b.integer; }
T2& operator%=(T2& t, int i)
{ t.integer %= i; return t; }
T2& operator%=(T2& a, const T2& b)
{ a.integer %= b.integer; return a; }
template<class T>
class T5 {
public:
T5(int);
T5(const T5<T>&);
~T5();
static void* operator new(size_t) throw ();
static void operator delete(void *pointer);
int value();
static T X;
T x;
int val;
};
template<class T>
T5<T>::T5(int v)
{ val = v; }
template<class T>
T5<T>::T5(const T5<T>&)
{}
template<class T>
T5<T>::~T5()
{}
template<class T>
void*
T5<T>::operator new(size_t) throw ()
{ return 0; }
template<class T>
void
T5<T>::operator delete(void *pointer)
{ }
template<class T>
int
T5<T>::value()
{ return val; }
template <class T>
T GetMax (T a, T b) {
T result;
result = (a>b)? a : b;
// set breakpoint on a line with no real code
return (result);
}
#if ! defined(__GNUC__) || defined(GCC_BUG)
template<class T>
T T5<T>::X;
#endif
T5<char> t5c(1);
T5<int> t5i(2);
T5<int (*)(char, void *)> t5fi1(3);
T5<int (*)(int, double **, void *)> t5fi2(4);
class x {
public:
int (*manage[5])(double,
void *(*malloc)(unsigned size),
void (*free)(void *pointer));
int (*device[5])(int open(const char *, unsigned mode, unsigned perms, int extra),
int *(*read)(int fd, void *place, unsigned size),
int *(*write)(int fd, void *place, unsigned size),
void (*close)(int fd));
};
T5<x> t5x(5);
#if !defined(__GNUC__) || (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6)
template class T5<char>;
template class T5<int>;
template class T5<int (*)(char, void *)>;
template class T5<int (*)(int, double **, void *)>;
template class T5<x>;
#endif
class T7 {
public:
static int get();
static void put(int);
};
int
T7::get()
{ return 1; }
void
T7::put(int i)
{
// nothing
}
// More template kinds. GDB 4.16 didn't handle these, but
// Wildebeest does. Note: Assuming HP aCC is used to compile
// this file; with g++ or HP cfront or other compilers the
// demangling may not get done correctly.
// Ordinary template, to be instantiated with different types
template<class T>
class Foo {
public:
int x;
T t;
T foo (int, T);
};
template<class T> T Foo<T>::foo (int i, T tt)
{
return tt;
}
// Template with int parameter
template<class T, int sz>
class Bar {
public:
int x;
T t;
T bar (int, T);
};
template<class T, int sz> T Bar<T, sz>::bar (int i, T tt)
{
if (i < sz)
return tt;
else
return 0;
}
// function template with int parameter
template<class T> int dummy (T tt, int i)
{
return tt;
}
// Template with partial specializations
template<class T1, class T2>
class Spec {
public:
int x;
T1 spec (T2);
};
template<class T1, class T2>
T1 Spec<T1, T2>::spec (T2 t2)
{
return 0;
}
template<class T>
class Spec<T, T*> {
public:
int x;
T spec (T*);
};
template<class T>
T Spec<T, T*>::spec (T * tp)
{
return *tp;
}
// Template with char parameter
template<class T, char sz>
class Baz {
public:
~Baz () { };
int x;
T t;
T baz (int, T);
};
template<class T, char sz> T Baz<T, sz>::baz (int i, T tt)
{
if (i < sz)
return tt;
else
return 0;
}
typedef Baz<int, 1> intBazOne;
// Template with char * parameter
template<class T, char * sz>
class Qux {
public:
int x;
T t;
T qux (int, T);
};
template<class T, char * sz> T Qux<T, sz>::qux (int i, T tt)
{
if (sz[0] == 'q')
return tt;
else
return 0;
}
// Template with a function pointer parameter
template<class T, int (*f)(int) >
class Qux1 {
public:
int x;
T t;
T qux (int, T);
};
template<class T, int (*f)(int)> T Qux1<T, f>::qux (int i, T tt)
{
if (f != 0)
return tt;
else
return 0;
}
// Some functions to provide as arguments to template
int gf1 (int a) {
return a * 2 + 13;
}
int gf2 (int a) {
return a * 2 + 26;
}
char string[3];
// Template class with typedefs and const attributes.
template<typename DataT>
class Cfoo
{
typedef float myfloat;
public:
DataT me0;
const DataT me1=1;
const myfloat me2=2.0;
const int me3=0;
};
// Template for nested instantiations
template<class T>
class Garply {
public:
int x;
T t;
T garply (int, T);
};
template<class T> T Garply<T>::garply (int i, T tt)
{
if (i > x)
return tt;
else
{
x += i;
return tt;
}
}
template<class C> class Empty
{
};
template<class C> class FunctionArg
{
public:
int method(Empty<void (FunctionArg<C>)> &);
};
template<class C> int FunctionArg<C>::method(Empty<void (FunctionArg<C>)> &arg)
{
return 75;
}
Empty<void(FunctionArg<int>)> empty;
FunctionArg<int> arg;
template <typename T1>
struct Foozle
{
int x;
T1 t;
template <typename T2>
T2 fogey (T2 plop);
};
template <typename T1>
template <typename T2>
T2 Foozle<T1>::fogey (T2 plop)
{
return plop;
}
template <typename T>
int operator< (T &lhs, T &rhs)
{
return 0;
}
template <typename T>
int operator<< (T &obj, T &val)
{
return 1;
};
int main()
{
int i;
long l, m, n;
i = i + 1;
// New tests added here
Foo<int> fint={0,0};
Foo<char> fchar={0,0};
Foo<volatile char *> fvpchar = {0, 0};
Bar<int, 33> bint;
Bar<int, (4 > 3)> bint2;
Baz<int, 's'> bazint;
Baz<char, 'a'> bazint2;
Qux<char, string> quxint2;
Qux<int, string> quxint;
Qux1<int, gf1> qux11;
int x = fint.foo(33, 47);
char c = fchar.foo(33, 'x');
volatile char * cp = fvpchar.foo(33, 0);
int y = dummy<int> (400, 600);
int z = bint.bar(55, 66);
z += bint2.bar(55, 66);
c = bazint2.baz(4, 'y');
c = quxint2.qux(4, 'z');
y = bazint.baz(4,3);
y = quxint.qux(4, 22);
y += qux11.qux(4, 22);
y *= gf1(y) - gf2(y);
Spec<int, char> sic;
Spec<int, int *> siip;
sic.spec ('c');
siip.spec (&x);
Cfoo<double> cfoo;
Garply<int> f;
Garply<char> fc;
f.x = 13;
Garply<Garply<char> > nf;
nf.x = 31;
x = f.garply (3, 4);
fc = nf.garply (3, fc);
y = x + fc.x;
i=GetMax<int>(x,y);
n=GetMax<long>(l,m);
intBazOne ibo;
z = ibo.baz (2, 21);
t5i.value();
arg.method(empty);
Empty<int> e;
Foozle<int> fzi;
x = fzi.fogey (0);
c = fzi.fogey<char> ('a');
e = fzi.fogey<Empty<int>> (e);
Foozle<char> fzc;
c = fzc.fogey ('b');
x = fzc.fogey<int> (0);
e = fzc.fogey<Empty<int>> (e);
Foozle<Empty<int>> fze;
e = fze.fogey (e);
c = fze.fogey<char> ('c');
x = fze.fogey<int> (0);
z = e < e;
z += e << e;
z += fzi < fzi;
z += fzi << fzi;
return 0; /* Final breakpoint. */
}