rtti.c revision 50397
1/* RunTime Type Identification
2   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3   Mostly written by Jason Merrill (jason@cygnus.com).
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.  */
21
22
23#include "config.h"
24#include "system.h"
25#include "tree.h"
26#include "cp-tree.h"
27#include "flags.h"
28#include "output.h"
29#include "assert.h"
30#include "toplev.h"
31
32#ifndef INT_TYPE_SIZE
33#define INT_TYPE_SIZE BITS_PER_WORD
34#endif
35
36extern struct obstack permanent_obstack;
37
38static tree call_void_fn PROTO((char *));
39static tree build_headof_sub PROTO((tree));
40static tree build_headof PROTO((tree));
41static tree get_tinfo_var PROTO((tree));
42static tree get_typeid_1 PROTO((tree));
43static tree ifnonnull PROTO((tree, tree));
44static tree build_dynamic_cast_1 PROTO((tree, tree));
45static void expand_si_desc PROTO((tree, tree));
46static void expand_class_desc PROTO((tree, tree));
47static void expand_attr_desc PROTO((tree, tree));
48static void expand_ptr_desc PROTO((tree, tree));
49static void expand_generic_desc PROTO((tree, tree, char *));
50static tree throw_bad_cast PROTO((void));
51static tree throw_bad_typeid PROTO((void));
52
53tree type_info_type_node;
54tree tinfo_fn_id;
55tree tinfo_fn_type;
56
57void
58init_rtti_processing ()
59{
60  if (flag_honor_std)
61    push_namespace (get_identifier ("std"));
62  type_info_type_node = xref_tag
63    (class_type_node, get_identifier ("type_info"), NULL_TREE, 1);
64  if (flag_honor_std)
65    pop_namespace ();
66  tinfo_fn_id = get_identifier ("__tf");
67  tinfo_fn_type = build_function_type
68    (build_reference_type (build_type_variant (type_info_type_node, 1, 0)),
69     void_list_node);
70}
71
72/* Given a pointer to an object with at least one virtual table
73   pointer somewhere, return a pointer to a possible sub-object that
74   has a virtual table pointer in it that is the vtable parent for
75   that sub-object.  */
76
77static tree
78build_headof_sub (exp)
79     tree exp;
80{
81  tree type = TREE_TYPE (TREE_TYPE (exp));
82  tree basetype = CLASSTYPE_RTTI (type);
83  tree binfo = get_binfo (basetype, type, 0);
84
85  exp = convert_pointer_to_real (binfo, exp);
86  return exp;
87}
88
89/* Given the expression EXP of type `class *', return the head of the
90   object pointed to by EXP with type cv void*, if the class has any
91   virtual functions (TYPE_VIRTUAL_P), else just return the
92   expression.  */
93
94static tree
95build_headof (exp)
96     tree exp;
97{
98  tree type = TREE_TYPE (exp);
99  tree aref;
100  tree offset;
101
102  if (TREE_CODE (type) != POINTER_TYPE)
103    {
104      error ("`headof' applied to non-pointer type");
105      return error_mark_node;
106    }
107  type = TREE_TYPE (type);
108
109  if (!TYPE_VIRTUAL_P (type))
110    return exp;
111
112  /* If we don't have rtti stuff, get to a sub-object that does.  */
113  if (!CLASSTYPE_VFIELDS (TREE_TYPE (TREE_TYPE (exp))))
114    exp = build_headof_sub (exp);
115
116  /* We use this a couple of times below, protect it.  */
117  exp = save_expr (exp);
118
119  aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node);
120
121  if (flag_vtable_thunks)
122    offset = aref;
123  else
124    offset = build_component_ref (aref, delta_identifier, NULL_TREE, 0);
125
126  type = build_type_variant (ptr_type_node, TREE_READONLY (exp),
127			     TREE_THIS_VOLATILE (exp));
128  return build (PLUS_EXPR, type, exp,
129		cp_convert (ptrdiff_type_node, offset));
130}
131
132/* Build a call to a generic entry point taking and returning void.  */
133
134static tree
135call_void_fn (name)
136     char *name;
137{
138  tree d = get_identifier (name);
139  tree type;
140
141  if (IDENTIFIER_GLOBAL_VALUE (d))
142    d = IDENTIFIER_GLOBAL_VALUE (d);
143  else
144    {
145      push_obstacks (&permanent_obstack, &permanent_obstack);
146
147      type = build_function_type (void_type_node, void_list_node);
148      d = build_lang_decl (FUNCTION_DECL, d, type);
149      DECL_EXTERNAL (d) = 1;
150      TREE_PUBLIC (d) = 1;
151      DECL_ARTIFICIAL (d) = 1;
152      pushdecl_top_level (d);
153      make_function_rtl (d);
154      assemble_external (d);
155
156      pop_obstacks ();
157    }
158
159  return build_call (d, void_type_node, NULL_TREE);
160}
161
162/* Get a bad_cast node for the program to throw...
163
164   See libstdc++/exception.cc for __throw_bad_cast */
165
166static tree
167throw_bad_cast ()
168{
169  return call_void_fn ("__throw_bad_cast");
170}
171
172static tree
173throw_bad_typeid ()
174{
175  return call_void_fn ("__throw_bad_typeid");
176}
177
178/* Return the type_info function associated with the expression EXP.  If
179   EXP is a reference to a polymorphic class, return the dynamic type;
180   otherwise return the static type of the expression.  */
181
182tree
183get_tinfo_fn_dynamic (exp)
184     tree exp;
185{
186  tree type;
187
188  if (exp == error_mark_node)
189    return error_mark_node;
190
191  if (type_unknown_p (exp))
192    {
193      error ("typeid of overloaded function");
194      return error_mark_node;
195    }
196
197  type = TREE_TYPE (exp);
198
199  /* peel back references, so they match.  */
200  if (TREE_CODE (type) == REFERENCE_TYPE)
201    type = TREE_TYPE (type);
202
203  /* Peel off cv qualifiers.  */
204  type = TYPE_MAIN_VARIANT (type);
205
206  /* If exp is a reference to polymorphic type, get the real type_info.  */
207  if (TYPE_VIRTUAL_P (type) && ! resolves_to_fixed_type_p (exp, 0))
208    {
209      /* build reference to type_info from vtable.  */
210      tree t;
211
212      if (! flag_rtti)
213	{
214	  warning ("taking dynamic typeid of object without -frtti");
215	  push_obstacks (&permanent_obstack, &permanent_obstack);
216	  init_rtti_processing ();
217	  pop_obstacks ();
218	  flag_rtti = 1;
219	}
220
221      /* If we don't have rtti stuff, get to a sub-object that does.  */
222      if (! CLASSTYPE_VFIELDS (type))
223	{
224	  exp = build_unary_op (ADDR_EXPR, exp, 0);
225	  exp = build_headof_sub (exp);
226	  exp = build_indirect_ref (exp, NULL_PTR);
227	}
228
229      if (flag_vtable_thunks)
230	t = build_vfn_ref ((tree *) 0, exp, integer_one_node);
231      else
232	t = build_vfn_ref ((tree *) 0, exp, integer_zero_node);
233      TREE_TYPE (t) = build_pointer_type (tinfo_fn_type);
234      return t;
235    }
236
237  /* otherwise return the type_info for the static type of the expr.  */
238  return get_tinfo_fn (TYPE_MAIN_VARIANT (type));
239}
240
241tree
242build_typeid (exp)
243     tree exp;
244{
245  exp = get_tinfo_fn_dynamic (exp);
246  exp = build_call (exp, TREE_TYPE (tinfo_fn_type), NULL_TREE);
247  return convert_from_reference (exp);
248}
249
250tree
251build_x_typeid (exp)
252     tree exp;
253{
254  tree cond = NULL_TREE;
255  tree type = TREE_TYPE (tinfo_fn_type);
256  int nonnull;
257
258  if (processing_template_decl)
259    return build_min_nt (TYPEID_EXPR, exp);
260
261  if (TREE_CODE (exp) == INDIRECT_REF
262      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
263      && TYPE_VIRTUAL_P (TREE_TYPE (exp))
264      && ! resolves_to_fixed_type_p (exp, &nonnull)
265      && ! nonnull)
266    {
267      exp = stabilize_reference (exp);
268      cond = cp_convert (boolean_type_node, TREE_OPERAND (exp, 0));
269    }
270
271  exp = get_tinfo_fn_dynamic (exp);
272
273  if (exp == error_mark_node)
274    return error_mark_node;
275
276  exp = build_call (exp, type, NULL_TREE);
277
278  if (cond)
279    {
280      tree bad = throw_bad_typeid ();
281
282      bad = build_compound_expr
283	(expr_tree_cons (NULL_TREE, bad, build_expr_list
284		    (NULL_TREE, cp_convert (type, integer_zero_node))));
285      exp = build (COND_EXPR, type, cond, exp, bad);
286    }
287
288  return convert_from_reference (exp);
289}
290
291static tree
292get_tinfo_var (type)
293     tree type;
294{
295  tree tname = build_overload_with_type (get_identifier ("__ti"), type);
296  tree tdecl, arrtype;
297  int size;
298
299  if (IDENTIFIER_GLOBAL_VALUE (tname))
300    return IDENTIFIER_GLOBAL_VALUE (tname);
301
302  /* Figure out how much space we need to allocate for the type_info object.
303     If our struct layout or the type_info classes are changed, this will
304     need to be modified.  */
305  if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
306    size = 3 * POINTER_SIZE + INT_TYPE_SIZE;
307  else if (TREE_CODE (type) == POINTER_TYPE
308	   && ! (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
309		 || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))
310    size = 3 * POINTER_SIZE;
311  else if (IS_AGGR_TYPE (type))
312    {
313      if (CLASSTYPE_N_BASECLASSES (type) == 0)
314	size = 2 * POINTER_SIZE;
315      else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
316	       && (TREE_VIA_PUBLIC
317		   (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
318	size = 3 * POINTER_SIZE;
319      else
320	size = 3 * POINTER_SIZE + TYPE_PRECISION (sizetype);
321    }
322  else
323    size = 2 * POINTER_SIZE;
324
325  push_obstacks (&permanent_obstack, &permanent_obstack);
326
327  /* The type for a character array of the appropriate size.  */
328  arrtype = build_cplus_array_type
329    (unsigned_char_type_node,
330     build_index_type (size_int (size / BITS_PER_UNIT - 1)));
331
332  tdecl = build_decl (VAR_DECL, tname, arrtype);
333  TREE_PUBLIC (tdecl) = 1;
334  DECL_EXTERNAL (tdecl) = 1;
335  DECL_ARTIFICIAL (tdecl) = 1;
336  pushdecl_top_level (tdecl);
337  cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
338
339  pop_obstacks ();
340
341  return tdecl;
342}
343
344tree
345get_tinfo_fn (type)
346     tree type;
347{
348  tree name;
349  tree d;
350
351  if (TREE_CODE (type) == OFFSET_TYPE)
352    type = TREE_TYPE (type);
353  if (TREE_CODE (type) == METHOD_TYPE)
354    type = build_function_type (TREE_TYPE (type),
355				TREE_CHAIN (TYPE_ARG_TYPES (type)));
356
357  name = build_overload_with_type (tinfo_fn_id, type);
358
359  if (IDENTIFIER_GLOBAL_VALUE (name))
360    return IDENTIFIER_GLOBAL_VALUE (name);
361
362  push_obstacks (&permanent_obstack, &permanent_obstack);
363
364  d = build_lang_decl (FUNCTION_DECL, name, tinfo_fn_type);
365  DECL_EXTERNAL (d) = 1;
366  TREE_PUBLIC (d) = 1;
367  DECL_ARTIFICIAL (d) = 1;
368  DECL_NOT_REALLY_EXTERN (d) = 1;
369  DECL_MUTABLE_P (d) = 1;
370  TREE_TYPE (name) = copy_to_permanent (type);
371
372  pushdecl_top_level (d);
373  make_function_rtl (d);
374  assemble_external (d);
375  mark_inline_for_output (d);
376  pop_obstacks ();
377
378  return d;
379}
380
381static tree
382get_typeid_1 (type)
383     tree type;
384{
385  tree t = build_call
386    (get_tinfo_fn (type), TREE_TYPE (tinfo_fn_type), NULL_TREE);
387  return convert_from_reference (t);
388}
389
390/* Return the type_info object for TYPE, creating it if necessary.  */
391
392tree
393get_typeid (type)
394     tree type;
395{
396  if (type == error_mark_node)
397    return error_mark_node;
398
399  if (! flag_rtti)
400    {
401      warning ("requesting typeid of object without -frtti");
402      push_obstacks (&permanent_obstack, &permanent_obstack);
403      init_rtti_processing ();
404      pop_obstacks ();
405      flag_rtti = 1;
406    }
407
408  if (processing_template_decl)
409    return build_min_nt (TYPEID_EXPR, type);
410
411  /* If the type of the type-id is a reference type, the result of the
412     typeid expression refers to a type_info object representing the
413     referenced type.  */
414  if (TREE_CODE (type) == REFERENCE_TYPE)
415    type = TREE_TYPE (type);
416
417  /* The top-level cv-qualifiers of the lvalue expression or the type-id
418     that is the operand of typeid are always ignored.  */
419  type = TYPE_MAIN_VARIANT (type);
420
421  return get_typeid_1 (type);
422}
423
424/* Check whether TEST is null before returning RESULT.  If TEST is used in
425   RESULT, it must have previously had a save_expr applied to it.  */
426
427static tree
428ifnonnull (test, result)
429     tree test, result;
430{
431  return build (COND_EXPR, TREE_TYPE (result),
432		build (EQ_EXPR, boolean_type_node, test, integer_zero_node),
433		cp_convert (TREE_TYPE (result), integer_zero_node),
434		result);
435}
436
437/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
438   paper.  */
439
440static tree
441build_dynamic_cast_1 (type, expr)
442     tree type, expr;
443{
444  enum tree_code tc = TREE_CODE (type);
445  tree exprtype = TREE_TYPE (expr);
446  enum tree_code ec;
447  tree dcast_fn;
448
449  assert (exprtype != NULL_TREE);
450  ec = TREE_CODE (exprtype);
451
452  switch (tc)
453    {
454    case POINTER_TYPE:
455      if (ec == REFERENCE_TYPE)
456	{
457	  expr = convert_from_reference (expr);
458	  exprtype = TREE_TYPE (expr);
459	  ec = TREE_CODE (exprtype);
460	}
461      if (ec != POINTER_TYPE)
462	goto fail;
463      if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE)
464	goto fail;
465      if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE)
466	goto fail;
467      if (TREE_READONLY (TREE_TYPE (exprtype))
468	  && ! TYPE_READONLY (TREE_TYPE (type)))
469	goto fail;
470      if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
471	break;
472      /* else fall through */
473    case REFERENCE_TYPE:
474      if (TREE_CODE (TREE_TYPE (type)) != RECORD_TYPE)
475	goto fail;
476      if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE)
477	goto fail;
478      break;
479      /* else fall through */
480    default:
481      goto fail;
482    }
483
484  /* Apply trivial conversion T -> T& for dereferenced ptrs.  */
485  if (ec == RECORD_TYPE)
486    {
487      exprtype = build_type_variant (exprtype, TREE_READONLY (expr),
488				     TREE_THIS_VOLATILE (expr));
489      exprtype = build_reference_type (exprtype);
490      expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
491				   LOOKUP_NORMAL, NULL_TREE);
492      ec = REFERENCE_TYPE;
493    }
494
495  if (tc == REFERENCE_TYPE)
496    {
497      if (ec != REFERENCE_TYPE)
498	goto fail;
499      if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE)
500	goto fail;
501      if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE)
502	goto fail;
503      if (TREE_READONLY (TREE_TYPE (exprtype))
504	  && ! TYPE_READONLY (TREE_TYPE (type)))
505	goto fail;
506    }
507
508  /* If *type is an unambiguous accessible base class of *exprtype,
509     convert statically.  */
510  {
511    int distance;
512    tree path;
513
514    distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
515				  &path);
516    if (distance >= 0)
517      return build_vbase_path (PLUS_EXPR, type, expr, path, 0);
518  }
519
520  /* Otherwise *exprtype must be a polymorphic class (have a vtbl).  */
521  if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype)))
522    {
523      tree expr1;
524      /* if TYPE is `void *', return pointer to complete object.  */
525      if (tc == POINTER_TYPE
526	  && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
527	{
528	  /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b.  */
529	  if (TREE_CODE (expr) == ADDR_EXPR
530	      && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL
531	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
532	    return build1 (NOP_EXPR, type, expr);
533
534	  /* Since expr is used twice below, save it.  */
535	  expr = save_expr (expr);
536
537	  expr1 = build_headof (expr);
538	  if (TREE_TYPE (expr1) != type)
539	    expr1 = build1 (NOP_EXPR, type, expr1);
540	  return ifnonnull (expr, expr1);
541	}
542      else
543	{
544	  tree retval;
545          tree result, td1, td2, td3, elems, expr2;
546
547 	  /* If we got here, we can't convert statically.  Therefore,
548	     dynamic_cast<D&>(b) (b an object) cannot succeed.  */
549	  if (ec == REFERENCE_TYPE)
550	    {
551	      if (TREE_CODE (expr) == VAR_DECL
552		  && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE)
553		{
554		  cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
555			      expr, type);
556		  return throw_bad_cast ();
557		}
558	    }
559	  /* Ditto for dynamic_cast<D*>(&b).  */
560	  else if (TREE_CODE (expr) == ADDR_EXPR)
561	    {
562	      tree op = TREE_OPERAND (expr, 0);
563	      if (TREE_CODE (op) == VAR_DECL
564		  && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)
565		{
566		  cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
567			      expr, type);
568		  retval = build_int_2 (0, 0);
569		  TREE_TYPE (retval) = type;
570		  return retval;
571		}
572	    }
573
574	  /* Since expr is used twice below, save it.  */
575	  expr = save_expr (expr);
576
577	  expr1 = expr;
578	  if (tc == REFERENCE_TYPE)
579	    expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
580
581	  /* Build run-time conversion.  */
582	  expr2 = build_headof (expr1);
583
584	  if (ec == POINTER_TYPE)
585	    td1 = get_tinfo_fn_dynamic (build_indirect_ref (expr, NULL_PTR));
586	  else
587	    td1 = get_tinfo_fn_dynamic (expr);
588	  td1 = decay_conversion (td1);
589
590	  td2 = decay_conversion
591	    (get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (type))));
592	  td3 = decay_conversion
593	    (get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (exprtype))));
594
595          elems = tree_cons
596	    (NULL_TREE, td1, tree_cons
597	     (NULL_TREE, td2, tree_cons
598	      (NULL_TREE, build_int_2 (1, 0), tree_cons
599	       (NULL_TREE, expr2, tree_cons
600		(NULL_TREE, td3, tree_cons
601		 (NULL_TREE, expr1, NULL_TREE))))));
602
603	  dcast_fn = get_identifier ("__dynamic_cast");
604	  if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
605	    dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
606	  else
607	    {
608	      tree tmp;
609
610	      push_obstacks (&permanent_obstack, &permanent_obstack);
611	      tmp = tree_cons
612		(NULL_TREE, TREE_TYPE (td1), tree_cons
613		 (NULL_TREE, TREE_TYPE (td1), tree_cons
614		  (NULL_TREE, integer_type_node, tree_cons
615		   (NULL_TREE, ptr_type_node, tree_cons
616		    (NULL_TREE, TREE_TYPE (td1), tree_cons
617		     (NULL_TREE, ptr_type_node, void_list_node))))));
618	      tmp = build_function_type (ptr_type_node, tmp);
619	      dcast_fn = build_lang_decl (FUNCTION_DECL, dcast_fn, tmp);
620	      DECL_EXTERNAL (dcast_fn) = 1;
621	      TREE_PUBLIC (dcast_fn) = 1;
622	      DECL_ARTIFICIAL (dcast_fn) = 1;
623	      pushdecl_top_level (dcast_fn);
624	      make_function_rtl (dcast_fn);
625	      assemble_external (dcast_fn);
626	      pop_obstacks ();
627	    }
628
629          result = build_call
630	    (dcast_fn, TREE_TYPE (TREE_TYPE (dcast_fn)), elems);
631
632	  if (tc == REFERENCE_TYPE)
633	    {
634	      expr1 = throw_bad_cast ();
635	      expr1 = build_compound_expr
636		(expr_tree_cons (NULL_TREE, expr1,
637			    build_expr_list (NULL_TREE, cp_convert (type, integer_zero_node))));
638	      TREE_TYPE (expr1) = type;
639	      result = save_expr (result);
640	      return build (COND_EXPR, type, result, result, expr1);
641	    }
642
643	  /* Now back to the type we want from a void*.  */
644	  result = cp_convert (type, result);
645          return ifnonnull (expr, result);
646	}
647    }
648
649 fail:
650  cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'",
651	    expr, exprtype, type);
652  return error_mark_node;
653}
654
655tree
656build_dynamic_cast (type, expr)
657     tree type, expr;
658{
659  if (type == error_mark_node || expr == error_mark_node)
660    return error_mark_node;
661
662  if (processing_template_decl)
663    return build_min (DYNAMIC_CAST_EXPR, copy_to_permanent (type), expr);
664
665  return convert_from_reference (build_dynamic_cast_1 (type, expr));
666}
667
668/* Build and initialize various sorts of descriptors.  Every descriptor
669   node has a name associated with it (the name created by mangling).
670   For this reason, we use the identifier as our access to the __*_desc
671   nodes, instead of sticking them directly in the types.  Otherwise we
672   would burden all built-in types (and pointer types) with slots that
673   we don't necessarily want to use.
674
675   For each descriptor we build, we build a variable that contains
676   the descriptor's information.  When we need this info at runtime,
677   all we need is access to these variables.
678
679   Note: these constructors always return the address of the descriptor
680   info, since that is simplest for their mutual interaction.  */
681
682extern tree const_string_type_node;
683
684/* Build an initializer for a __si_type_info node.  */
685
686static void
687expand_si_desc (tdecl, type)
688     tree tdecl;
689     tree type;
690{
691  tree t, elems, fn;
692  char *name = build_overload_name (type, 1, 1);
693  tree name_string = combine_strings (build_string (strlen (name)+1, name));
694
695  type = BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0));
696  expand_expr_stmt (get_typeid_1 (type));
697  t = decay_conversion (get_tinfo_var (type));
698  elems = tree_cons
699    (NULL_TREE, decay_conversion (tdecl), tree_cons
700     (NULL_TREE, decay_conversion (name_string), tree_cons
701      (NULL_TREE, t, NULL_TREE)));
702
703  fn = get_identifier ("__rtti_si");
704  if (IDENTIFIER_GLOBAL_VALUE (fn))
705    fn = IDENTIFIER_GLOBAL_VALUE (fn);
706  else
707    {
708      tree tmp;
709      push_obstacks (&permanent_obstack, &permanent_obstack);
710      tmp = tree_cons
711	(NULL_TREE, ptr_type_node, tree_cons
712	 (NULL_TREE, const_string_type_node, tree_cons
713	  (NULL_TREE, build_pointer_type (type_info_type_node),
714	   void_list_node)));
715      tmp = build_function_type	(void_type_node, tmp);
716
717      fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
718      DECL_EXTERNAL (fn) = 1;
719      TREE_PUBLIC (fn) = 1;
720      DECL_ARTIFICIAL (fn) = 1;
721      pushdecl_top_level (fn);
722      make_function_rtl (fn);
723      assemble_external (fn);
724      pop_obstacks ();
725    }
726
727  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
728  expand_expr_stmt (fn);
729}
730
731/* Build an initializer for a __class_type_info node.  */
732
733static void
734expand_class_desc (tdecl, type)
735     tree tdecl;
736     tree type;
737{
738  tree name_string;
739  tree fn, tmp;
740  char *name;
741
742  int i = CLASSTYPE_N_BASECLASSES (type);
743  int base_cnt = 0;
744  tree binfos = TYPE_BINFO_BASETYPES (type);
745#if 0
746  /* See code below that used these.  */
747  tree vb = CLASSTYPE_VBASECLASSES (type);
748  int n_base = i;
749#endif
750  tree base, elems, access, offset, isvir;
751  tree elt, elts = NULL_TREE;
752  static tree base_info_type_node;
753
754  if (base_info_type_node == NULL_TREE)
755    {
756      tree fields [4];
757
758      /* A reasonably close approximation of __class_type_info::base_info */
759
760      push_obstacks (&permanent_obstack, &permanent_obstack);
761      base_info_type_node = make_lang_type (RECORD_TYPE);
762
763      /* Actually const __user_type_info * */
764      fields [0] = build_lang_field_decl
765	(FIELD_DECL, NULL_TREE,
766	 build_pointer_type (build_type_variant (type_info_type_node, 1, 0)));
767      fields [1] = build_lang_field_decl
768	(FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
769      DECL_BIT_FIELD (fields[1]) = 1;
770      DECL_FIELD_SIZE (fields[1]) = 29;
771
772      fields [2] = build_lang_field_decl
773	(FIELD_DECL, NULL_TREE, boolean_type_node);
774      DECL_BIT_FIELD (fields[2]) = 1;
775      DECL_FIELD_SIZE (fields[2]) = 1;
776
777      /* Actually enum access */
778      fields [3] = build_lang_field_decl
779	(FIELD_DECL, NULL_TREE, integer_type_node);
780      DECL_BIT_FIELD (fields[3]) = 1;
781      DECL_FIELD_SIZE (fields[3]) = 2;
782
783      finish_builtin_type (base_info_type_node, "__base_info", fields,
784			   3, ptr_type_node);
785      pop_obstacks ();
786    }
787
788  while (--i >= 0)
789    {
790      tree binfo = TREE_VEC_ELT (binfos, i);
791
792      expand_expr_stmt (get_typeid_1 (BINFO_TYPE (binfo)));
793      base = decay_conversion (get_tinfo_var (BINFO_TYPE (binfo)));
794
795      if (TREE_VIA_VIRTUAL (binfo))
796	{
797	  tree t = BINFO_TYPE (binfo);
798	  char *name;
799	  tree field;
800
801	  name = (char *) alloca (TYPE_NAME_LENGTH (t)+sizeof (VBASE_NAME)+1);
802	  sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (t));
803	  field = lookup_field (type, get_identifier (name), 0, 0);
804	  offset = size_binop (FLOOR_DIV_EXPR,
805		DECL_FIELD_BITPOS (field), size_int (BITS_PER_UNIT));
806	  offset = convert (sizetype, offset);
807	}
808      else
809	offset = BINFO_OFFSET (binfo);
810
811      if (TREE_VIA_PUBLIC (binfo))
812        access = access_public_node;
813      else if (TREE_VIA_PROTECTED (binfo))
814	access = access_protected_node;
815      else
816	access = access_private_node;
817      if (TREE_VIA_VIRTUAL (binfo))
818	isvir = boolean_true_node;
819      else
820	isvir = boolean_false_node;
821
822      elt = build
823	(CONSTRUCTOR, base_info_type_node, NULL_TREE, tree_cons
824	 (NULL_TREE, base, tree_cons
825	  (NULL_TREE, offset, tree_cons
826	   (NULL_TREE, isvir, tree_cons
827	    (NULL_TREE, access, NULL_TREE)))));
828      TREE_HAS_CONSTRUCTOR (elt) = TREE_CONSTANT (elt) = TREE_STATIC (elt) = 1;
829      elts = expr_tree_cons (NULL_TREE, elt, elts);
830      base_cnt++;
831    }
832#if 0
833  i = n_base;
834  while (vb)
835    {
836      tree b;
837      access = access_public_node;
838      while (--i >= 0)
839	{
840	  b = TREE_VEC_ELT (binfos, i);
841	  if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b))
842	    {
843	      if (TREE_VIA_PUBLIC (b))
844		access = access_public_node;
845	      else if (TREE_VIA_PROTECTED (b))
846		access = access_protected_node;
847	      else
848		access = access_private_node;
849	      break;
850	    }
851	}
852      base = build_t_desc (BINFO_TYPE (vb), 1);
853      offset = BINFO_OFFSET (vb);
854      isvir = build_int_2 (1, 0);
855
856      base_list = expr_tree_cons (NULL_TREE, base, base_list);
857      isvir_list = expr_tree_cons (NULL_TREE, isvir, isvir_list);
858      acc_list = expr_tree_cons (NULL_TREE, access, acc_list);
859      off_list = expr_tree_cons (NULL_TREE, offset, off_list);
860
861      base_cnt++;
862      vb = TREE_CHAIN (vb);
863    }
864#endif
865
866  name = build_overload_name (type, 1, 1);
867  name_string = combine_strings (build_string (strlen (name)+1, name));
868
869  {
870    tree arrtype = build_array_type (base_info_type_node, NULL_TREE);
871    elts = build (CONSTRUCTOR, arrtype, NULL_TREE, elts);
872    TREE_HAS_CONSTRUCTOR (elts) = TREE_CONSTANT (elts)
873      = TREE_STATIC (elts) = 1;
874    complete_array_type (arrtype, elts, 1);
875  }
876
877  elems = tree_cons
878    (NULL_TREE, decay_conversion (tdecl), tree_cons
879     (NULL_TREE, decay_conversion (name_string), tree_cons
880      (NULL_TREE, decay_conversion (elts), tree_cons
881       (NULL_TREE, cp_convert (sizetype, build_int_2 (base_cnt, 0)),
882	NULL_TREE))));
883
884  fn = get_identifier ("__rtti_class");
885  if (IDENTIFIER_GLOBAL_VALUE (fn))
886    fn = IDENTIFIER_GLOBAL_VALUE (fn);
887  else
888    {
889      push_obstacks (&permanent_obstack, &permanent_obstack);
890      tmp = tree_cons
891	(NULL_TREE, ptr_type_node, tree_cons
892	 (NULL_TREE, const_string_type_node, tree_cons
893	  (NULL_TREE, build_pointer_type (base_info_type_node), tree_cons
894	   (NULL_TREE, sizetype, void_list_node))));
895      tmp = build_function_type	(void_type_node, tmp);
896
897      fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
898      DECL_EXTERNAL (fn) = 1;
899      TREE_PUBLIC (fn) = 1;
900      DECL_ARTIFICIAL (fn) = 1;
901      pushdecl_top_level (fn);
902      make_function_rtl (fn);
903      assemble_external (fn);
904      pop_obstacks ();
905    }
906
907  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
908  expand_expr_stmt (fn);
909}
910
911/* Build an initializer for a __pointer_type_info node.  */
912
913static void
914expand_ptr_desc (tdecl, type)
915     tree tdecl;
916     tree type;
917{
918  tree t, elems, fn;
919  char *name = build_overload_name (type, 1, 1);
920  tree name_string = combine_strings (build_string (strlen (name)+1, name));
921
922  type = TREE_TYPE (type);
923  expand_expr_stmt (get_typeid_1 (type));
924  t = decay_conversion (get_tinfo_var (type));
925  elems = tree_cons
926    (NULL_TREE, decay_conversion (tdecl), tree_cons
927     (NULL_TREE, decay_conversion (name_string), tree_cons
928      (NULL_TREE, t, NULL_TREE)));
929
930  fn = get_identifier ("__rtti_ptr");
931  if (IDENTIFIER_GLOBAL_VALUE (fn))
932    fn = IDENTIFIER_GLOBAL_VALUE (fn);
933  else
934    {
935      tree tmp;
936      push_obstacks (&permanent_obstack, &permanent_obstack);
937      tmp = tree_cons
938	(NULL_TREE, ptr_type_node, tree_cons
939	 (NULL_TREE, const_string_type_node, tree_cons
940	  (NULL_TREE, build_pointer_type (type_info_type_node),
941	   void_list_node)));
942      tmp = build_function_type	(void_type_node, tmp);
943
944      fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
945      DECL_EXTERNAL (fn) = 1;
946      TREE_PUBLIC (fn) = 1;
947      DECL_ARTIFICIAL (fn) = 1;
948      pushdecl_top_level (fn);
949      make_function_rtl (fn);
950      assemble_external (fn);
951      pop_obstacks ();
952    }
953
954  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
955  expand_expr_stmt (fn);
956}
957
958/* Build an initializer for a __attr_type_info node.  */
959
960static void
961expand_attr_desc (tdecl, type)
962     tree tdecl;
963     tree type;
964{
965  tree elems, t, fn;
966  char *name = build_overload_name (type, 1, 1);
967  tree name_string = combine_strings (build_string (strlen (name)+1, name));
968  tree attrval = build_int_2
969    (TYPE_READONLY (type) | TYPE_VOLATILE (type) * 2, 0);
970
971  expand_expr_stmt (get_typeid_1 (TYPE_MAIN_VARIANT (type)));
972  t = decay_conversion (get_tinfo_var (TYPE_MAIN_VARIANT (type)));
973  elems = tree_cons
974    (NULL_TREE, decay_conversion (tdecl), tree_cons
975     (NULL_TREE, decay_conversion (name_string), tree_cons
976      (NULL_TREE, attrval, expr_tree_cons (NULL_TREE, t, NULL_TREE))));
977
978  fn = get_identifier ("__rtti_attr");
979  if (IDENTIFIER_GLOBAL_VALUE (fn))
980    fn = IDENTIFIER_GLOBAL_VALUE (fn);
981  else
982    {
983      tree tmp;
984      push_obstacks (&permanent_obstack, &permanent_obstack);
985      tmp = tree_cons
986	(NULL_TREE, ptr_type_node, tree_cons
987	 (NULL_TREE, const_string_type_node, tree_cons
988	  (NULL_TREE, integer_type_node, tree_cons
989	   (NULL_TREE, build_pointer_type (type_info_type_node),
990	    void_list_node))));
991      tmp = build_function_type	(void_type_node, tmp);
992
993      fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
994      DECL_EXTERNAL (fn) = 1;
995      TREE_PUBLIC (fn) = 1;
996      DECL_ARTIFICIAL (fn) = 1;
997      pushdecl_top_level (fn);
998      make_function_rtl (fn);
999      assemble_external (fn);
1000      pop_obstacks ();
1001    }
1002
1003  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
1004  expand_expr_stmt (fn);
1005}
1006
1007/* Build an initializer for a type_info node that just has a name.  */
1008
1009static void
1010expand_generic_desc (tdecl, type, fnname)
1011     tree tdecl;
1012     tree type;
1013     char *fnname;
1014{
1015  char *name = build_overload_name (type, 1, 1);
1016  tree name_string = combine_strings (build_string (strlen (name)+1, name));
1017  tree elems = tree_cons
1018    (NULL_TREE, decay_conversion (tdecl), tree_cons
1019     (NULL_TREE, decay_conversion (name_string), NULL_TREE));
1020
1021  tree fn = get_identifier (fnname);
1022  if (IDENTIFIER_GLOBAL_VALUE (fn))
1023    fn = IDENTIFIER_GLOBAL_VALUE (fn);
1024  else
1025    {
1026      tree tmp;
1027      push_obstacks (&permanent_obstack, &permanent_obstack);
1028      tmp = tree_cons
1029	(NULL_TREE, ptr_type_node, tree_cons
1030	 (NULL_TREE, const_string_type_node, void_list_node));
1031      tmp = build_function_type (void_type_node, tmp);
1032
1033      fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
1034      DECL_EXTERNAL (fn) = 1;
1035      TREE_PUBLIC (fn) = 1;
1036      DECL_ARTIFICIAL (fn) = 1;
1037      pushdecl_top_level (fn);
1038      make_function_rtl (fn);
1039      assemble_external (fn);
1040      pop_obstacks ();
1041    }
1042
1043  fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
1044  expand_expr_stmt (fn);
1045}
1046
1047/* Generate the code for a type_info initialization function.
1048   Note that we take advantage of the passage
1049
1050   5.2.7  Type identification                               [expr.typeid]
1051
1052   Whether or not the destructor is called for the type_info object at the
1053   end of the program is unspecified.
1054
1055   and don't bother to arrange for these objects to be destroyed.  It
1056   doesn't matter, anyway, since the destructors don't do anything.
1057
1058   This must only be called from toplevel (i.e. from finish_file)!  */
1059
1060void
1061synthesize_tinfo_fn (fndecl)
1062     tree fndecl;
1063{
1064  tree type = TREE_TYPE (DECL_NAME (fndecl));
1065  tree tmp, addr, tdecl;
1066
1067  if (at_eof)
1068    {
1069      import_export_decl (fndecl);
1070      if (DECL_REALLY_EXTERN (fndecl))
1071	return;
1072    }
1073
1074  tdecl = get_tinfo_var (type);
1075  DECL_EXTERNAL (tdecl) = 0;
1076  TREE_STATIC (tdecl) = 1;
1077  DECL_COMMON (tdecl) = 1;
1078  TREE_USED (tdecl) = 1;
1079  DECL_ALIGN (tdecl) = TYPE_ALIGN (ptr_type_node);
1080  cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
1081
1082  start_function (NULL_TREE, fndecl, NULL_TREE, 1);
1083  store_parm_decls ();
1084  clear_last_expr ();
1085  push_momentary ();
1086
1087  /* If the first word of the array (the vtable) is non-zero, we've already
1088     initialized the object, so don't do it again.  */
1089  addr = decay_conversion (tdecl);
1090  tmp = cp_convert (build_pointer_type (ptr_type_node), addr);
1091  tmp = build_indirect_ref (tmp, 0);
1092  tmp = build_binary_op (EQ_EXPR, tmp, integer_zero_node, 1);
1093  expand_start_cond (tmp, 0);
1094
1095  if (TREE_CODE (type) == FUNCTION_TYPE)
1096    expand_generic_desc (tdecl, type, "__rtti_func");
1097  else if (TREE_CODE (type) == ARRAY_TYPE)
1098    expand_generic_desc (tdecl, type, "__rtti_array");
1099  else if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
1100    expand_attr_desc (tdecl, type);
1101  else if (TREE_CODE (type) == POINTER_TYPE)
1102    {
1103      if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
1104	expand_generic_desc (tdecl, type, "__rtti_ptmd");
1105      else if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
1106	expand_generic_desc (tdecl, type, "__rtti_ptmf");
1107      else
1108	expand_ptr_desc (tdecl, type);
1109    }
1110  else if (TYPE_PTRMEMFUNC_P (type))
1111    expand_generic_desc (tdecl, type, "__rtti_ptmf");
1112  else if (IS_AGGR_TYPE (type))
1113    {
1114      if (CLASSTYPE_N_BASECLASSES (type) == 0)
1115	expand_generic_desc (tdecl, type, "__rtti_user");
1116      else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
1117	       && (TREE_VIA_PUBLIC
1118		   (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
1119	expand_si_desc (tdecl, type);
1120      else
1121	expand_class_desc (tdecl, type);
1122    }
1123  else if (TREE_CODE (type) == ENUMERAL_TYPE)
1124    expand_generic_desc (tdecl, type, "__rtti_user");
1125  else
1126    my_friendly_abort (252);
1127
1128  expand_end_cond ();
1129
1130  /* OK, now return the type_info object.  */
1131  tmp = cp_convert (build_pointer_type (type_info_type_node), addr);
1132  tmp = build_indirect_ref (tmp, 0);
1133  c_expand_return (tmp);
1134  finish_function (lineno, 0, 0);
1135}
1136