/* This testcase is part of GDB, the GNU debugger.

   Copyright 2008-2023 Free Software Foundation, Inc.

   Contributed by Red Hat, originally written by Keith Seitz.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

   Please email any bugs, comments, and/or additions to this file to:
   bug-gdb@gnu.org  */

#include <stdlib.h>
#include <iostream>

// Forward decls
class base;
class derived;

// A simple template with specializations
template <typename T>
class tclass
{
public:
  void do_something () { } // tclass<T>::do_something
};

template <>
void tclass<char>::do_something () { } // tclass<char>::do_something

template <>
void tclass<int>::do_something () { } // tclass<int>::do_something

template<>
void tclass<long>::do_something () { } // tclass<long>::do_something

template<>
void tclass<short>::do_something () { } // tclass<short>::do_something

// A simple template with multiple template parameters
template <class A, class B, class C, class D, class E>
void flubber (void) { // flubber
  A a;
  B b;
  C c;
  D d;
  E e;

  ++a;
  ++b;
  ++c;
  ++d;
  ++e;
}

// Some contrived policies
template <class T>
struct operation_1
{
  static void function (void) { } // operation_1<T>::function
};

template <class T>
struct operation_2
{
  static void function (void) { } // operation_2<T>::function
};

template <class T>
struct operation_3
{
  static void function (void) { } // operation_3<T>::function
};

template <class T>
struct operation_4
{
  static void function (void) { } // operation_4<T>::function
};

// A policy-based class w/ and w/o default policy
template <class T, class Policy>
class policy : public Policy
{
public:
  policy (T obj) : obj_ (obj) { } // policy<T, Policy>::policy

private:
  T obj_;
};

template <class T, class Policy = operation_1<T> >
class policyd : public Policy
{
public:
  policyd (T obj) : obj_ (obj) { } // policyd<T, Policy>::policyd
  ~policyd (void) { } // policyd<T, Policy>::~policyd

private:
  T obj_;
};

typedef policy<int, operation_1<void*> > policy1;
typedef policy<int, operation_2<void*> > policy2;
typedef policy<int, operation_3<void*> > policy3;
typedef policy<int, operation_4<void*> > policy4;

typedef policyd<int> policyd1;
typedef policyd<long> policyd2;
typedef policyd<char> policyd3;
typedef policyd<base> policyd4;
typedef policyd<tclass<int> > policyd5;

class fluff { };
static fluff *g_fluff = new fluff ();

class base
{
protected:
  int foo_;

public:
  base (void) : foo_ (42) { } // base::base(void)
  base (int foo) : foo_ (foo) { } // base::base(int)
  ~base (void) { } // base::~base

  // Some overloaded methods
  int overload (void) const { return 0; } // base::overload(void) const
  int overload (int i) const { return 1; } // base::overload(int) const
  int overload (short s) const { return 2; } // base::overload(short) const
  int overload (long l) const { return 3; } // base::overload(long) const
  int overload (char* a) const { return 4; } // base::overload(char*) const
  int overload (base& b) const { return 5; } // base::overload(base&) const

  // Operators
  int operator+ (base const& o) const { // base::operator+
    return foo_ + o.foo_;  }

  base operator++ (void) { // base::operator++
    ++foo_; return *this; }

  base operator+=(base const& o) { // base::operator+=
    foo_ += o.foo_; return *this; }

  int operator- (base const& o) const { // base::operator-
    return foo_ - o.foo_; }

  base operator-- (void) { // base::operator--
    --foo_; return *this; }

  base operator-= (base const& o) { // base::operator-=
    foo_ -= o.foo_; return *this; }

  int operator* (base const& o) const { // base::operator*
    return foo_ * o.foo_; }

  base operator*= (base const& o) { // base::operator*=
    foo_ *= o.foo_; return *this; }

  int operator/ (base const& o) const { // base::operator/
    return foo_ / o.foo_; }

  base operator/= (base const& o) { // base::operator/=
    foo_ /= o.foo_; return *this; }

  int operator% (base const& o) const { // base::operator%
    return foo_ % o.foo_; }
  
  base operator%= (base const& o) { // base::operator%=
    foo_ %= o.foo_; return *this; }

  bool operator< (base const& o) const { // base::operator<
    return foo_ < o.foo_; }

  bool operator<= (base const& o) const { // base::operator<=
    return foo_ <= o.foo_; }

  bool operator> (base const& o) const { // base::operator>
    return foo_ > o.foo_; }

  bool operator>= (base const& o) const { // base::operator>=
    return foo_ >= o.foo_; }

  bool operator!= (base const& o) const { // base::operator!=
    return foo_ != o.foo_; }

  bool operator== (base const& o) const { // base::operator==
    return foo_ == o.foo_; }

  bool operator! (void) const { // base::operator!
    return !foo_; }

  bool operator&& (base const& o) const { // base::operator&&
    return foo_ && o.foo_; }

  bool operator|| (base const& o) const { // base::operator||
    return foo_ || o.foo_; }

  int operator<< (int value) const { // base::operator<<
    return foo_  << value; }

  base operator<<= (int value) { // base::operator<<=
    foo_ <<= value; return *this; }

  int operator>> (int value) const { // base::operator>>
    return foo_  >> value; }

  base operator>>= (int value) { // base::operator>>=
    foo_ >>= value; return *this; }

  int operator~ (void) const { // base::operator~
    return ~foo_; }

  int operator& (base const& o) const { // base::operator&
    return foo_ & o.foo_; }

  base operator&= (base const& o) { // base::operator&=
    foo_ &= o.foo_; return *this; }

  int operator| (base const& o) const { // base::operator|
    return foo_ | o.foo_; }

  base operator|= (base const& o) { // base::operator|=
    foo_ |= o.foo_; return *this; }
  
  int operator^ (base const& o) const { // base::operator^
    return foo_ ^ o.foo_; }

  base operator^= (base const& o) { // base::operator^=
    foo_ ^= o.foo_; return *this; }

  base operator= (base const& o) { // base::operator=
    foo_ = o.foo_; return *this; }

  void operator() (void) const { // base::operator()
    return; }

  int operator[] (int idx) const { // base::operator[]
    return idx; }

  void* operator new (size_t size) throw () { // base::operator new
    return malloc (size); }

  void operator delete (void* ptr) { // base::operator delete
    free (ptr); }

  void* operator new[] (size_t size) throw () { // base::operator new[]
    return malloc (size); }

  void operator delete[] (void* ptr) { // base::operator delete[]
    free (ptr); }

  base const* operator-> (void) const { // base::opeartor->
    return this; }

  int operator->* (base const& b) const { // base::operator->*
    return foo_ * b.foo_; }

  operator char* () const { return const_cast<char*> ("hello"); } // base::operator char*
  operator int () const { return 21; } // base::operator int
  operator fluff* () const { return new fluff (); } // base::operator fluff*
  operator fluff** () const { return &g_fluff; } // base::operator fluff**
  operator fluff const* const* () const { return &g_fluff; } // base::operator fluff const* const*
};

class base1 : public virtual base
{
public:
  base1 (void) : foo_ (21) { } // base1::base1(void)
  base1 (int a) : foo_(a) { } // base1::base1(int)
  void a_function (void) const { } // base1::a_function

protected:
  int foo_;
};

class base2 : public virtual base
{
public:
  base2 () : foo_ (3) { } // base2::base2

protected:
  void a_function (void) const { } // base2::a_function
  int foo_;
};

class derived : public base1, public base2
{
  public:
  derived(void) : foo_ (4) { } // derived::derived
  void a_function (void) const { // derived::a_function
    this->base1::a_function ();
    this->base2::a_function ();
  }

  protected:
  int foo_;
};

class CV { public:
  static const int i;
  typedef int t;
  void m(t);
  void m(t) const;
  void m(t) volatile;
  void m(t) const volatile;
};
const int CV::i = 42;
#ifdef __GNUC__
# define ATTRIBUTE_USED __attribute__((used))
#else
# define ATTRIBUTE_USED
#endif
ATTRIBUTE_USED void CV::m(CV::t) {}
ATTRIBUTE_USED void CV::m(CV::t) const {}
ATTRIBUTE_USED void CV::m(CV::t) volatile {}
ATTRIBUTE_USED void CV::m(CV::t) const volatile {}
int CV_f (int x)
{
  return x + 1;
}

int
test_function (int argc, char* argv[]) // test_function
{ // test_function
  derived d;
  void (derived::*pfunc) (void) const = &derived::a_function;
  (d.*pfunc) ();

  base a (1), b (3), c (8);
  (void) a.overload ();
  (void) a.overload (static_cast<int> (0));
  (void) a.overload (static_cast<short> (0));
  (void) a.overload (static_cast<long> (0));
  (void) a.overload (static_cast<char*> (0));
  (void) a.overload (a);

  int r;
  r = b + c;
  ++a;
  a += b;
  r = b - c;
  --a;
  a -= b;
  r = b * c;
  a *= b;
  r = b / c;
  a /= b;
  r = b % c;
  a %= b;
  bool x = (b < c);
  x = (b <= c);
  x = (b > c);
  x = (b >= c);
  x = (b != c);
  x = (b == c);
  x = (!b);
  x = (b && c);
  x = (b || c);
  r = b << 2;
  a <<= 1;
  r = b >> 2;
  a >>= 1;
  r = ~b;
  r = b & c;
  a &= c;
  r = b | c;
  a |= c;
  r = b ^ c;
  a ^= c;
  a = c;
  a ();
  int i = a[3];
  derived* f = new derived ();
  derived* g = new derived[3];
  delete f;
  delete[] g;
  a->overload ();
  r = a->*b;

  tclass<char> char_tclass;
  tclass<int> int_tclass;
  tclass<short> short_tclass;
  tclass<long> long_tclass;
  tclass<base> base_tclass;
  char_tclass.do_something ();
  int_tclass.do_something ();
  short_tclass.do_something ();
  long_tclass.do_something ();
  base_tclass.do_something ();

  flubber<int, int, int, int, int> ();
  flubber<int, int, int, int, short> ();
  flubber<int, int, int, int, long> ();
  flubber<int, int, int, int, char> ();
  flubber<int, int, int, short, int> ();
  flubber<int, int, int, short, short> ();
  flubber<int, int, int, short, long> ();
  flubber<int, int, int, short, char> ();
  flubber<int, int, int, long, int> ();
  flubber<int, int, int, long, short> ();
  flubber<int, int, int, long, long> ();
  flubber<int, int, int, long, char> ();
  flubber<int, int, int, char, int> ();
  flubber<int, int, int, char, short> ();
  flubber<int, int, int, char, long> ();
  flubber<int, int, int, char, char> ();
  flubber<int, int, short, int, int> ();
  flubber<int, int, short, int, short> ();
  flubber<int, int, short, int, long> ();
  flubber<int, int, short, int, char> ();
  flubber<int, int, short, short, int> ();
  flubber<short, int, short, int, short> ();
  flubber<long, short, long, short, long> ();

  policy1 p1 (1);
  p1.function ();
  policy2 p2 (2);
  p2.function ();
  policy3 p3 (3);
  p3.function ();
  policy4 p4 (4);
  p4.function ();

  policyd1 pd1 (5);
  pd1.function ();
  policyd2 pd2 (6);
  pd2.function ();
  policyd3 pd3 (7);
  pd3.function ();
  policyd4 pd4 (d);
  pd4.function ();
  policyd5 pd5 (int_tclass);
  pd5.function ();

  base1 b1 (3);

  r = a;
  char* str = a;
  fluff* flp = a;
  fluff** flpp = a;
  fluff const* const* flcpcp = a;

  CV_f(CV::i);

  return 0;
}

int
main (int argc, char* argv[])
{
  int i;

  /* Call the test function repeatedly, enough times for all our tests
     without running forever if something goes wrong.  */
  for (i = 0; i < 1000; i++)
    test_function (argc, argv);

  return 0;
}
