| // Methods for type_info for -*- C++ -*- Run Time Type Identification. |
| // Copyright (C) 1994, 1996 Free Software Foundation |
| |
| // This file is part of GNU CC. |
| |
| // GNU CC 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 2, or (at your option) |
| // any later version. |
| |
| // GNU CC 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 GNU CC; see the file COPYING. If not, write to |
| // the Free Software Foundation, 59 Temple Place - Suite 330, |
| // Boston, MA 02111-1307, USA. |
| |
| // As a special exception, if you link this library with other files, |
| // some of which are compiled with GCC, to produce an executable, |
| // this library does not by itself cause the resulting executable |
| // to be covered by the GNU General Public License. |
| // This exception does not however invalidate any other reasons why |
| // the executable file might be covered by the GNU General Public License. |
| |
| #include <stddef.h> |
| #include "tinfo.h" |
| #include "new" // for placement new |
| |
| // service function for comparing types by name. |
| |
| static inline int |
| fast_compare (const char *n1, const char *n2) { |
| int c; |
| if (n1 == n2) return 0; |
| if (n1 == 0) return *n2; |
| else if (n2 == 0) return *n1; |
| |
| c = (int)*n1++ - (int)*n2++; |
| return c == 0 ? strcmp (n1, n2) : c; |
| }; |
| |
| bool |
| type_info::before (const type_info &arg) const |
| { |
| return fast_compare (name (), arg.name ()) < 0; |
| } |
| |
| #ifdef _WIN32 |
| bool type_info:: |
| operator== (const type_info& arg) const |
| { |
| return fast_compare (name (), arg.name ()) == 0; |
| } |
| |
| bool type_info:: |
| operator!= (const type_info& arg) const |
| { |
| return fast_compare (name (), arg.name ()) != 0; |
| } |
| #endif |
| |
| // type info for pointer type. |
| |
| struct __pointer_type_info : public type_info { |
| const type_info& type; |
| |
| __pointer_type_info (const char *n, const type_info& ti) |
| : type_info (n), type (ti) {} |
| }; |
| |
| // type info for attributes |
| |
| struct __attr_type_info : public type_info { |
| enum cv { NONE = 0, CONST = 1, VOLATILE = 2, CONSTVOL = 1 | 2 }; |
| |
| const type_info& type; |
| cv attr; |
| |
| __attr_type_info (const char *n, cv a, const type_info& t) |
| : type_info (n), type (t), attr (a) {} |
| }; |
| |
| // type_info for builtin type |
| |
| struct __builtin_type_info : public type_info { |
| __builtin_type_info (const char *n): type_info (n) {} |
| }; |
| |
| // type info for function. |
| |
| struct __func_type_info : public type_info { |
| __func_type_info (const char *n) : type_info (n) {} |
| }; |
| |
| // type info for pointer to member function. |
| |
| struct __ptmf_type_info : public type_info { |
| __ptmf_type_info (const char *n) : type_info (n) {} |
| }; |
| |
| // type info for pointer to data member. |
| |
| struct __ptmd_type_info : public type_info { |
| __ptmd_type_info (const char *n): type_info (n) {} |
| }; |
| |
| // type info for array. |
| |
| struct __array_type_info : public type_info { |
| __array_type_info (const char *n): type_info (n) {} |
| }; |
| |
| // Entry points for the compiler. |
| |
| /* Low level match routine used by compiler to match types of catch |
| variables and thrown objects. */ |
| |
| extern "C" void* |
| __throw_type_match_rtti (void *catch_type_r, void *throw_type_r, void *objptr) |
| { |
| const type_info &catch_type = *(const type_info *)catch_type_r; |
| const type_info &throw_type = *(const type_info *)throw_type_r; |
| |
| if (catch_type == throw_type) |
| return objptr; |
| |
| #if 0 |
| printf ("We want to match a %s against a %s!\n", |
| throw_type.name (), catch_type.name ()); |
| #endif |
| |
| void *new_objptr = 0; |
| |
| if (const __user_type_info *p |
| = dynamic_cast <const __user_type_info *> (&throw_type)) |
| { |
| /* The 1 skips conversions to private bases. */ |
| new_objptr = p->dcast (catch_type, 1, objptr); |
| } |
| else if (const __pointer_type_info *fr = |
| dynamic_cast <const __pointer_type_info *> (&throw_type)) |
| { |
| const __pointer_type_info *to = |
| dynamic_cast <const __pointer_type_info *> (&catch_type); |
| |
| if (! to) |
| goto fail; |
| |
| const type_info *subfr = &fr->type, *subto = &to->type; |
| __attr_type_info::cv cvfrom, cvto; |
| |
| if (const __attr_type_info *at |
| = dynamic_cast <const __attr_type_info *> (subfr)) |
| { |
| cvfrom = at->attr; |
| subfr = &at->type; |
| } |
| else |
| cvfrom = __attr_type_info::NONE; |
| |
| if (const __attr_type_info *at |
| = dynamic_cast <const __attr_type_info *> (subto)) |
| { |
| cvto = at->attr; |
| subto = &at->type; |
| } |
| else |
| cvto = __attr_type_info::NONE; |
| |
| if (((cvfrom & __attr_type_info::CONST) |
| > (cvto & __attr_type_info::CONST)) |
| || ((cvfrom & __attr_type_info::VOLATILE) |
| > (cvto & __attr_type_info::VOLATILE))) |
| goto fail; |
| |
| if (*subto == *subfr) |
| new_objptr = objptr; |
| else if (*subto == typeid (void) |
| && dynamic_cast <const __func_type_info *> (subfr) == 0) |
| new_objptr = objptr; |
| else if (const __user_type_info *p |
| = dynamic_cast <const __user_type_info *> (subfr)) |
| { |
| /* The 1 skips conversions to private bases. */ |
| new_objptr = p->dcast (*subto, 1, objptr); |
| } |
| else if (const __pointer_type_info *pfr |
| = dynamic_cast <const __pointer_type_info *> (subfr)) |
| { |
| // Multi-level pointer conversion. |
| |
| const __pointer_type_info *pto |
| = dynamic_cast <const __pointer_type_info *> (subto); |
| |
| if (! pto) |
| goto fail; |
| |
| bool constp = (cvto & __attr_type_info::CONST); |
| for (subto = &pto->type, subfr = &pfr->type; ; |
| subto = &pto->type, subfr = &pfr->type) |
| { |
| if (const __attr_type_info *at |
| = dynamic_cast <const __attr_type_info *> (subfr)) |
| { |
| cvfrom = at->attr; |
| subfr = &at->type; |
| } |
| else |
| cvfrom = __attr_type_info::NONE; |
| |
| if (const __attr_type_info *at |
| = dynamic_cast <const __attr_type_info *> (subto)) |
| { |
| cvto = at->attr; |
| subto = &at->type; |
| } |
| else |
| cvto = __attr_type_info::NONE; |
| |
| if (((cvfrom & __attr_type_info::CONST) |
| > (cvto & __attr_type_info::CONST)) |
| || ((cvfrom & __attr_type_info::VOLATILE) |
| > (cvto & __attr_type_info::VOLATILE))) |
| goto fail; |
| |
| if (! constp |
| && (((cvfrom & __attr_type_info::CONST) |
| < (cvto & __attr_type_info::CONST)) |
| || ((cvfrom & __attr_type_info::VOLATILE) |
| < (cvto & __attr_type_info::VOLATILE)))) |
| goto fail; |
| |
| if (*subto == *subfr) |
| { |
| new_objptr = objptr; |
| break; |
| } |
| |
| pto = dynamic_cast <const __pointer_type_info *> (subto); |
| pfr = dynamic_cast <const __pointer_type_info *> (subfr); |
| if (! pto || ! pfr) |
| goto fail; |
| |
| if (! (cvto & __attr_type_info::CONST)) |
| constp = false; |
| } |
| } |
| } |
| fail: |
| |
| #if 0 |
| if (new_objptr) |
| printf ("It converts, delta is %d\n", new_objptr-objptr); |
| #endif |
| return new_objptr; |
| } |
| |
| extern "C" void |
| __rtti_ptr (void *addr, const char *n, const type_info *ti) |
| { new (addr) __pointer_type_info (n, *ti); } |
| |
| extern "C" void |
| __rtti_attr (void *addr, const char *n, int attrval, const type_info *ti) |
| { |
| new (addr) __attr_type_info |
| (n, static_cast <__attr_type_info::cv> (attrval), *ti); |
| } |
| |
| extern "C" void |
| __rtti_func (void *addr, const char *name) |
| { new (addr) __func_type_info (name); } |
| |
| extern "C" void |
| __rtti_ptmf (void *addr, const char *name) |
| { new (addr) __ptmf_type_info (name); } |
| |
| extern "C" void |
| __rtti_ptmd (void *addr, const char *name) |
| { new (addr) __ptmd_type_info (name); } |
| |
| extern "C" void |
| __rtti_array (void *addr, const char *name) |
| { new (addr) __array_type_info (name); } |
| |
| extern "C" void * |
| __dynamic_cast (const type_info& (*from)(void), const type_info& (*to)(void), |
| int require_public, void *address, |
| const type_info & (*sub)(void), void *subptr) |
| { |
| return static_cast <const __user_type_info &> (from ()).dcast |
| (to (), require_public, address, &(sub ()), subptr); |
| } |
| |
| // type_info nodes and functions for the builtin types. The mangling here |
| // must match the mangling in gcc/cp/rtti.c. |
| |
| #define BUILTIN(mangled) \ |
| unsigned char __ti##mangled [sizeof (__builtin_type_info)] \ |
| __attribute__ ((aligned (__alignof__ (void *)))); \ |
| extern "C" const type_info &__tf##mangled (void) { \ |
| if ((*(void **) __ti##mangled) == 0) \ |
| new (__ti##mangled) __builtin_type_info (#mangled); \ |
| return *(type_info *)__ti##mangled; \ |
| } |
| |
| BUILTIN (v); BUILTIN (x); BUILTIN (l); BUILTIN (i); BUILTIN (s); BUILTIN (b); |
| BUILTIN (c); BUILTIN (w); BUILTIN (r); BUILTIN (d); BUILTIN (f); |
| BUILTIN (Ui); BUILTIN (Ul); BUILTIN (Ux); BUILTIN (Us); BUILTIN (Uc); |