• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2016-2022 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the private implementation of the suppression engine
11 /// of libabigail.
12 
13 #ifndef __ABG_IR_PRIV_H__
14 #define __ABG_IR_PRIV_H__
15 
16 #include <string>
17 #include <iostream>
18 
19 #include "abg-ir.h"
20 #include "abg-corpus.h"
21 
22 namespace abigail
23 {
24 
25 namespace ir
26 {
27 
28 using std::string;
29 using abg_compat::optional;
30 
31 /// The result of structural comparison of type ABI artifacts.
32 enum comparison_result
33 {
34   COMPARISON_RESULT_DIFFERENT = 0,
35   COMPARISON_RESULT_EQUAL = 1,
36   COMPARISON_RESULT_CYCLE_DETECTED = 2,
37   COMPARISON_RESULT_UNKNOWN = 3,
38 }; //end enum comparison_result
39 
40 /// The internal representation of an integral type.
41 ///
42 /// This is a "utility type" used internally to canonicalize the name
43 /// of fundamental integral types, so that "unsignd long" and "long
44 /// unsined int" end-up having the same name.
45 class integral_type
46 {
47 public:
48   /// The possible base types of integral types.  We might have
49   /// forgotten many of these, so do not hesitate to add new ones.
50   ///
51   /// If you do add new ones, please also consider updating functions
52   /// parse_base_integral_type and integral_type::to_string.
53   enum base_type
54   {
55     /// The "int" base type.
56     INT_BASE_TYPE,
57     /// The "char" base type.
58     CHAR_BASE_TYPE,
59     /// The "bool" base type in C++ or "_Bool" in C11.
60     BOOL_BASE_TYPE,
61     /// The "double" base type.
62     DOUBLE_BASE_TYPE,
63     /// The "float" base type.
64     FLOAT_BASE_TYPE,
65     /// The "char16_t base type.
66     CHAR16_T_BASE_TYPE,
67     /// The "char32_t" base type.
68     CHAR32_T_BASE_TYPE,
69     /// The "wchar_t" base type.
70     WCHAR_T_BASE_TYPE
71   };
72 
73   /// The modifiers of the base types above.  Several modifiers can be
74   /// combined for a given base type.  The presence of modifiers is
75   /// usually modelled by a bitmap of modifiers.
76   ///
77   /// If you add a new modifier, please consider updating functions
78   /// parse_integral_type_modifier and integral_type::to_string.
79   enum modifiers_type
80   {
81     NO_MODIFIER = 0,
82     /// The "signed" modifier.
83     SIGNED_MODIFIER = 1,
84     /// The "unsigned" modier.
85     UNSIGNED_MODIFIER = 1 << 1,
86     /// The "short" modifier.
87     SHORT_MODIFIER = 1 << 2,
88     /// The "long" modifier.
89     LONG_MODIFIER = 1 << 3,
90     /// The "long long" modifier.
91     LONG_LONG_MODIFIER = 1 << 4
92   };
93 
94 private:
95   base_type	base_;
96   modifiers_type modifiers_;
97 
98 public:
99 
100   integral_type();
101   integral_type(const string& name);
102   integral_type(base_type, modifiers_type);
103 
104   base_type
105   get_base_type() const;
106 
107   modifiers_type
108   get_modifiers() const;
109 
110   void
111   set_modifiers(modifiers_type);
112 
113   bool
114   operator==(const integral_type&) const;
115 
116   string
117   to_string(bool internal=false) const;
118 
119   operator string() const;
120 }; // end class integral_type
121 
122 integral_type::modifiers_type
123 operator|(integral_type::modifiers_type l, integral_type::modifiers_type r);
124 
125 integral_type::modifiers_type
126 operator&(integral_type::modifiers_type l, integral_type::modifiers_type r);
127 
128 integral_type::modifiers_type
129 operator~(integral_type::modifiers_type l);
130 
131 integral_type::modifiers_type&
132 operator|=(integral_type::modifiers_type& l, integral_type::modifiers_type r);
133 
134 integral_type::modifiers_type&
135 operator &=(integral_type::modifiers_type& l, integral_type::modifiers_type r);
136 
137 bool
138 parse_integral_type(const string& type_name,
139 		    integral_type& type);
140 
141 /// Private type to hold private members of @ref translation_unit
142 struct translation_unit::priv
143 {
144   const environment&				env_;
145   corpus*					corp;
146   bool						is_constructed_;
147   char						address_size_;
148   language					language_;
149   std::string					path_;
150   std::string					comp_dir_path_;
151   std::string					abs_path_;
152   location_manager				loc_mgr_;
153   mutable global_scope_sptr			global_scope_;
154   mutable vector<type_base_sptr>		synthesized_types_;
155   vector<function_type_sptr>			live_fn_types_;
156   type_maps					types_;
157 
158 
privpriv159   priv(const environment& env)
160     : env_(env),
161       corp(),
162       is_constructed_(),
163       address_size_(),
164       language_(LANG_UNKNOWN)
165   {}
166 
~privpriv167   ~priv()
168   {}
169 
170   type_maps&
get_typespriv171   get_types()
172   {return types_;}
173 }; // end translation_unit::priv
174 
175 // <type_base definitions>
176 
177 /// Definition of the private data of @ref type_base.
178 struct type_base::priv
179 {
180   size_t		size_in_bits;
181   size_t		alignment_in_bits;
182   type_base_wptr	canonical_type;
183   // The data member below holds the canonical type that is managed by
184   // the smart pointer referenced by the canonical_type data member
185   // above.  We are storing this underlying (naked) pointer here, so
186   // that users can access it *fast*.  Otherwise, accessing
187   // canonical_type above implies creating a shared_ptr, and that has
188   // been measured to be slow for some performance hot spots.
189   type_base*		naked_canonical_type;
190   // Computing the representation of a type again and again can be
191   // costly.  So we cache the internal and non-internal type
192   // representation strings here.
193   interned_string	internal_cached_repr_;
194   interned_string	cached_repr_;
195   // The next two data members are used while comparing types during
196   // canonicalization.  They are useful for the "canonical type
197   // propagation" (aka on-the-fly-canonicalization) optimization
198   // implementation.
199 
200   // The set of canonical recursive types this type depends on.
201   unordered_set<uintptr_t> depends_on_recursive_type_;
202   bool canonical_type_propagated_;
203   bool propagated_canonical_type_confirmed_;
204 
privpriv205   priv()
206     : size_in_bits(),
207       alignment_in_bits(),
208       naked_canonical_type(),
209       canonical_type_propagated_(false),
210       propagated_canonical_type_confirmed_(false)
211   {}
212 
213   priv(size_t s,
214        size_t a,
215        type_base_sptr c = type_base_sptr())
size_in_bitspriv216     : size_in_bits(s),
217       alignment_in_bits(a),
218       canonical_type(c),
219       naked_canonical_type(c.get()),
220       canonical_type_propagated_(false),
221       propagated_canonical_type_confirmed_(false)
222   {}
223 
224   /// Test if the current type depends on recursive type comparison.
225   ///
226   /// A recursive type T is a type T which has a sub-type that is T
227   /// (recursively) itself.
228   ///
229   /// So this function tests if the current type has a recursive
230   /// sub-type or is a recursive type itself.
231   ///
232   /// @return true if the current type depends on a recursive type.
233   bool
depends_on_recursive_typepriv234   depends_on_recursive_type() const
235   {return !depends_on_recursive_type_.empty();}
236 
237   /// Test if the current type depends on a given recursive type.
238   ///
239   /// A recursive type T is a type T which has a sub-type that is T
240   /// (recursively) itself.
241   ///
242   /// So this function tests if the current type depends on a given
243   /// recursive type.
244   ///
245   /// @param dependant the type we want to test if the current type
246   /// depends on.
247   ///
248   /// @return true if the current type depends on the recursive type
249   /// @dependant.
250   bool
depends_on_recursive_typepriv251   depends_on_recursive_type(const type_base* dependant) const
252   {
253     return
254       (depends_on_recursive_type_.find(reinterpret_cast<uintptr_t>(dependant))
255        != depends_on_recursive_type_.end());
256   }
257 
258   /// Set the flag that tells if the current type depends on a given
259   /// recursive type.
260   ///
261   /// A recursive type T is a type T which has asub-type that is T
262   /// (recursively) itself.
263   ///
264   /// So this function tests if the current type depends on a
265   /// recursive type.
266   ///
267   /// @param t the recursive type that current type depends on.
268   void
set_depends_on_recursive_typepriv269   set_depends_on_recursive_type(const type_base * t)
270   {depends_on_recursive_type_.insert(reinterpret_cast<uintptr_t>(t));}
271 
272   /// Unset the flag that tells if the current type depends on a given
273   /// recursive type.
274   ///
275   /// A recursive type T is a type T which has asub-type that is T
276   /// (recursively) itself.
277   ///
278   /// So this function flags the current type as not being dependant
279   /// on a given recursive type.
280   ///
281   ///
282   /// @param t the recursive type to consider.
283   void
set_does_not_depend_on_recursive_typepriv284   set_does_not_depend_on_recursive_type(const type_base *t)
285   {depends_on_recursive_type_.erase(reinterpret_cast<uintptr_t>(t));}
286 
287   /// Flag the current type as not being dependant on any recursive type.
288   void
set_does_not_depend_on_recursive_typepriv289   set_does_not_depend_on_recursive_type()
290   {depends_on_recursive_type_.clear();}
291 
292   /// Test if the type carries a canonical type that is the result of
293   /// maybe_propagate_canonical_type(), aka, "canonical type
294   /// propagation optimization".
295   ///
296   /// @return true iff the current type carries a canonical type that
297   /// is the result of canonical type propagation.
298   bool
canonical_type_propagatedpriv299   canonical_type_propagated()
300   {return canonical_type_propagated_;}
301 
302   /// Set the flag that says if the type carries a canonical type that
303   /// is the result of maybe_propagate_canonical_type(), aka,
304   /// "canonical type propagation optimization".
305   ///
306   /// @param f true iff the current type carries a canonical type that
307   /// is the result of canonical type propagation.
308   void
set_canonical_type_propagatedpriv309   set_canonical_type_propagated(bool f)
310   {canonical_type_propagated_ = f;}
311 
312   /// Getter of the property propagated-canonical-type-confirmed.
313   ///
314   /// If canonical_type_propagated() returns true, then this property
315   /// says if the propagated canonical type has been confirmed or not.
316   /// If it hasn't been confirmed, then it means it can still
317   /// cancelled.
318   ///
319   /// @return true iff the propagated canonical type has been
320   /// confirmed.
321   bool
propagated_canonical_type_confirmedpriv322   propagated_canonical_type_confirmed() const
323   {return propagated_canonical_type_confirmed_;}
324 
325   /// Setter of the property propagated-canonical-type-confirmed.
326   ///
327   /// If canonical_type_propagated() returns true, then this property
328   /// says if the propagated canonical type has been confirmed or not.
329   /// If it hasn't been confirmed, then it means it can still
330   /// cancelled.
331   ///
332   /// @param f If this is true then the propagated canonical type has
333   /// been confirmed.
334   void
set_propagated_canonical_type_confirmedpriv335   set_propagated_canonical_type_confirmed(bool f)
336   {propagated_canonical_type_confirmed_ = f;}
337 
338   /// If the current canonical type was set as the result of the
339   /// "canonical type propagation optimization", then clear it.
340   void
clear_propagated_canonical_typepriv341   clear_propagated_canonical_type()
342   {
343     if (canonical_type_propagated_ && !propagated_canonical_type_confirmed_)
344       {
345 	canonical_type.reset();
346 	naked_canonical_type = nullptr;
347 	set_canonical_type_propagated(false);
348       }
349   }
350 }; // end struct type_base::priv
351 
352 // <environment definitions>
353 
354 /// The hashing functor for a pair of uint64_t.
355 struct uint64_t_pair_hash
356 {
357   /// Hashing function for a pair of uint64_t.
358   ///
359   /// @param p the pair to hash.
360   uint64_t
operatoruint64_t_pair_hash361   operator()(const std::pair<uint64_t, uint64_t>& p) const
362   {return abigail::hashing::combine_hashes(p.first, p.second);}
363 };
364 
365 /// A convenience typedef for a pair of uint64_t which is initially
366 /// intended to store a pair of pointer values.
367 typedef std::pair<uint64_t, uint64_t> uint64_t_pair_type;
368 
369 /// A convenience typedef for a set of @ref uint64_t_pair
370 typedef unordered_set<uint64_t_pair_type,
371 		      uint64_t_pair_hash> uint64_t_pairs_set_type;
372 /// A convenience typedef for a map which key is a pair of uint64_t
373 /// and which value is a boolean.  This is initially intended to cache
374 /// the result of comparing two (sub-)types.
375 typedef unordered_map<uint64_t_pair_type, bool,
376 		      uint64_t_pair_hash> type_comparison_result_type;
377 
378 /// The private data of the @ref environment type.
379 struct environment::priv
380 {
381   config				config_;
382   canonical_types_map_type		canonical_types_;
383   mutable vector<type_base_sptr>	sorted_canonical_types_;
384   type_base_sptr			void_type_;
385   type_base_sptr			variadic_marker_type_;
386   // The set of pairs of class types being currently compared.  It's
387   // used to avoid endless loops while recursively comparing types.
388   // This should be empty when none of the 'equal' overloads are
389   // currently being invoked.
390   uint64_t_pairs_set_type		classes_being_compared_;
391   // The set of pairs of function types being currently compared.  It's used
392   // to avoid endless loops while recursively comparing types.  This
393   // should be empty when none of the 'equal' overloads are currently
394   // being invoked.
395   uint64_t_pairs_set_type		fn_types_being_compared_;
396   // This is a cache for the result of comparing two sub-types (of
397   // either class or function types) that are designated by their
398   // memory address in the IR.
399   type_comparison_result_type		type_comparison_results_cache_;
400   vector<type_base_sptr>		extra_live_types_;
401   interned_string_pool			string_pool_;
402   // The two vectors below represent the stack of left and right
403   // operands of the current type comparison operation that is
404   // happening during type canonicalization.
405   //
406   // Basically, that stack of operand looks like below.
407   //
408   // First, suppose we have a type T_L that has two sub-types as this:
409   //
410   //  T_L
411   //   |
412   //   +-- L_OP0
413   //   |
414   //   +-- L_OP1
415   //
416   // Now suppose that we have another type T_R that has two sub-types
417   // as this:
418   //
419   //  T_R
420   //   |
421   //   +-- R_OP0
422   //   |
423   //   +-- R_OP1
424   //
425   //   Now suppose that we compare T_L against T_R.  We are going to
426   //   have a stack of pair of types. Each pair of types represents
427   //   two (sub) types being compared against each other.
428   //
429   //   On the stack, we will thus first have the pair (T_L, T_R)
430   //   being compared.  Then, we will have the pair (L_OP0, R_OP0)
431   //   being compared, and then the pair (L_OP1, R_OP1) being
432   //   compared.  Like this:
433   //
434   // | T_L | L_OP0 | L_OP1 | <-- this goes into left_type_comp_operands_;
435   //  -------- -------------
436   // | T_R | R_OP0 | R_OP1 | <-- this goes into right_type_comp_operands_;
437   //
438   // This "stack of operands of the current type comparison, during
439   // type canonicalization" is used in the context of the @ref
440   // OnTheFlyCanonicalization optimization.  It's used to detect if a
441   // sub-type of the type being canonicalized depends on a recursive
442   // type.
443   vector<const type_base*>		left_type_comp_operands_;
444   vector<const type_base*>		right_type_comp_operands_;
445   // Vector of types that protentially received propagated canonical types.
446   // If the canonical type propagation is confirmed, the potential
447   // canonical types must be promoted as canonical types. Otherwise if
448   // the canonical type propagation is cancelled, the canonical types
449   // must be cleared.
450   pointer_set		types_with_non_confirmed_propagated_ct_;
451   pointer_set		recursive_types_;
452 #ifdef WITH_DEBUG_SELF_COMPARISON
453   // This is used for debugging purposes.
454   // When abidw is used with the option --debug-abidiff, some
455   // libabigail internals need to get a hold on the initial binary
456   // input of abidw, as well as as the abixml file that represents the
457   // ABI of that binary.
458   //
459   // So this one is the corpus for the input binary.
460   corpus_wptr				first_self_comparison_corpus_;
461   // This one is the corpus for the ABIXML file representing the
462   // serialization of the input binary.
463   corpus_wptr				second_self_comparison_corpus_;
464   // This is also used for debugging purposes, when using
465   //   'abidw --debug-abidiff <binary>'.  It holds the set of mapping of
466   // an abixml (canonical) type and its type-id.
467   unordered_map<string, uintptr_t>	type_id_canonical_type_map_;
468   // Likewise.  It holds a map that associates the pointer to a type
469   // read from abixml and the type-id string it corresponds to.
470   unordered_map<uintptr_t, string>	pointer_type_id_map_;
471 #endif
472   bool					canonicalization_is_done_;
473   bool					do_on_the_fly_canonicalization_;
474   bool					decl_only_class_equals_definition_;
475   bool					use_enum_binary_only_equality_;
476   bool					allow_type_comparison_results_caching_;
477   optional<bool>			analyze_exported_interfaces_only_;
478 #ifdef WITH_DEBUG_SELF_COMPARISON
479   bool					self_comparison_debug_on_;
480 #endif
481 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
482   // This controls whether to use canonical type comparison during
483   // type comparison or not.  This is only used for debugging, when we
484   // want to ensure that comparing types using canonical or structural
485   // comparison yields the same result.
486   bool					use_canonical_type_comparison_;
487   // Whether we are debugging type canonicalization or not.  When
488   // debugging type canonicalization, a type is compared to its
489   // potential canonical type twice: The first time with canonical
490   // comparison activated, and the second time with structural
491   // comparison activated.  The two comparison should yield the same
492   // result, otherwise, canonicalization is "broken" for that
493   // particular type.
494   bool					debug_type_canonicalization_;
495   bool					debug_die_canonicalization_;
496 #endif
497 
privpriv498   priv()
499     : canonicalization_is_done_(),
500       do_on_the_fly_canonicalization_(true),
501       decl_only_class_equals_definition_(false),
502       use_enum_binary_only_equality_(true),
503       allow_type_comparison_results_caching_(false)
504 #ifdef WITH_DEBUG_SELF_COMPARISON
505     ,
506       self_comparison_debug_on_(false)
507 #endif
508 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
509     ,
510       use_canonical_type_comparison_(true),
511       debug_type_canonicalization_(false),
512       debug_die_canonicalization_(false)
513 #endif
514   {}
515 
516   /// Allow caching of the sub-types comparison results during the
517   /// invocation of the @ref equal overloads for class and function
518   /// types.
519   ///
520   /// @param f if true, allow type comparison result caching.
521   void
allow_type_comparison_results_cachingpriv522   allow_type_comparison_results_caching(bool f)
523   {allow_type_comparison_results_caching_ = f;}
524 
525   /// Check whether if caching of the sub-types comparison results during the
526   /// invocation of the @ref equal overloads for class and function
527   /// types is in effect.
528   ///
529   /// @return true iff caching of the sub-types comparison results
530   /// during the invocation of the @ref equal overloads for class and
531   /// function types is in effect.
532   bool
allow_type_comparison_results_cachingpriv533   allow_type_comparison_results_caching() const
534   {return allow_type_comparison_results_caching_;}
535 
536   /// Cache the result of comparing two sub-types.
537   ///
538   /// @param first the first sub-type that has been compared. Its
539   /// address is going to be stored in the cache.
540   ///
541   /// @param second the second sub-type that has been compared. Its
542   /// address is going to be stored in the cache.
543   ///
544   /// @param r the result of comparing @p first and @p second.  This
545   /// is going to be stored in the cache, as well as the addresses of
546   /// @p first and @p second.
547   template<typename T>
548   void
cache_type_comparison_resultpriv549   cache_type_comparison_result(T& first, T& second, bool r)
550   {
551     if (allow_type_comparison_results_caching()
552 	&& (r == false
553 	    ||
554 	    (!is_recursive_type(&first)
555 	     && !is_recursive_type(&second)
556 	     && !is_type(&first)->priv_->depends_on_recursive_type()
557 	     && !is_type(&second)->priv_->depends_on_recursive_type())))
558       {
559 	type_comparison_results_cache_.emplace
560 	  (std::make_pair(reinterpret_cast<uint64_t>(&first),
561 			  reinterpret_cast<uint64_t>(&second)),
562 	   r);
563       }
564   }
565 
566   /// Retrieve the result of comparing two sub-types from the cache,
567   /// if it was previously stored.
568   ///
569   /// @param first the first sub-type to consider.
570   ///
571   /// @param second the second sub-type to consider.  The pair of
572   /// addresses of {@p first, @p second} is going to be looked up in
573   /// the cache.  If it's present, then the associated result of the
574   /// comparison of @p first against @p second is present as well, and
575   /// is returned.
576   ///
577   /// @param r this is an out parameter which is set to the result of
578   /// the comparison of @p first against @p second if the pair of
579   /// addresses of {@p first, @p second} is present in the cache.
580   ///
581   /// @return true iff the pair of addresses of {@p first, @p second}
582   /// is present in the cache.  In that case, the associated result of
583   /// the comparison of @p first against @p second is returned in the
584   /// argument of @p r.
585   template<typename T>
586   bool
is_type_comparison_cachedpriv587   is_type_comparison_cached(T& first, T& second, bool& r)
588   {
589     if (!allow_type_comparison_results_caching())
590       return false;
591 
592     type_comparison_result_type::const_iterator it =
593       type_comparison_results_cache_.find
594 	 (std::make_pair(reinterpret_cast<uint64_t>(&first),
595 			 reinterpret_cast<uint64_t>(&second)));
596     if (it == type_comparison_results_cache_.end())
597       return false;
598 
599     r = it->second;
600     return true;
601   }
602 
603   /// Clear the cache type comparison results.
604   void
clear_type_comparison_results_cachepriv605   clear_type_comparison_results_cache()
606   {type_comparison_results_cache_.clear();}
607 
608   /// Dumps a textual representation (to the standard error output) of
609   /// the content of the set of classes being currently compared using
610   /// the @ref equal overloads.
611   ///
612   /// This function is for debugging purposes.
613   void
dump_classes_being_comparedpriv614   dump_classes_being_compared()
615   {
616     std::cerr << "classes being compared: " << classes_being_compared_.size()
617 	      << "\n"
618 	      << "=====================================\n";
619     for (auto& p : classes_being_compared_)
620       {
621 	class_or_union* c = reinterpret_cast<class_or_union*>(p.first);
622 	std::cerr << "'" << c->get_pretty_representation()
623 		  << " / (" << std::hex << p.first << "," << p.second << ")"
624 		  << "'\n";
625       }
626     std::cerr << "=====================================\n";
627   }
628 
629   /// Dumps a textual representation (to the standard error output) of
630   /// the content of the set of classes being currently compared using
631   /// the @ref equal overloads.
632   ///
633   /// This function is for debugging purposes.
634   void
dump_fn_types_being_comparedpriv635   dump_fn_types_being_compared()
636   {
637     std::cerr << "fn_types being compared: " << fn_types_being_compared_.size()
638 	      << "\n"
639 	      << "=====================================\n";
640     for (auto& p : fn_types_being_compared_)
641       {
642 	function_type* c = reinterpret_cast<function_type*>(p.first);
643 	std::cerr << "'" << c->get_pretty_representation()
644 		  << " / (" << std::hex << p.first << "," << p.second << ")"
645 		  << "'\n";
646       }
647     std::cerr << "=====================================\n";
648   }
649 
650   /// Push a pair of operands on the stack of operands of the current
651   /// type comparison, during type canonicalization.
652   ///
653   /// For more information on this, please look at the description of
654   /// the right_type_comp_operands_ data member.
655   ///
656   /// @param left the left-hand-side comparison operand to push.
657   ///
658   /// @param right the right-hand-side comparison operand to push.
659   void
push_composite_type_comparison_operandspriv660   push_composite_type_comparison_operands(const type_base* left,
661 					  const type_base* right)
662   {
663     ABG_ASSERT(left && right);
664 
665     left_type_comp_operands_.push_back(left);
666     right_type_comp_operands_.push_back(right);
667   }
668 
669   /// Pop a pair of operands from the stack of operands to the current
670   /// type comparison.
671   ///
672   /// For more information on this, please look at the description of
673   /// the right_type_comp_operands_ data member.
674   ///
675   /// @param left the left-hand-side comparison operand we expect to
676   /// pop from the top of the stack.  If this doesn't match the
677   /// operand found on the top of the stack, the function aborts.
678   ///
679   /// @param right the right-hand-side comparison operand we expect to
680   /// pop from the bottom of the stack. If this doesn't match the
681   /// operand found on the top of the stack, the function aborts.
682   void
pop_composite_type_comparison_operandspriv683   pop_composite_type_comparison_operands(const type_base* left,
684 					 const type_base* right)
685   {
686     const type_base *t = left_type_comp_operands_.back();
687     ABG_ASSERT(t == left);
688     t = right_type_comp_operands_.back();
689     ABG_ASSERT(t == right);
690 
691     left_type_comp_operands_.pop_back();
692     right_type_comp_operands_.pop_back();
693   }
694 
695   /// Mark all the types that comes after a certain one as NOT being
696   /// eligible for the canonical type propagation optimization.
697   ///
698   /// @param type the type that represents the "marker type".  All
699   /// types after this one will be marked as being NON-eligible to
700   /// the canonical type propagation optimization.
701   ///
702   /// @param types the set of types to consider.  In that vector, all
703   /// types that come after @p type are going to be marked as being
704   /// non-eligible to the canonical type propagation optimization.
705   ///
706   /// @return true iff the operation was successful.
707   bool
mark_dependant_typespriv708   mark_dependant_types(const type_base* type,
709 		       vector<const type_base*>& types)
710   {
711     bool found = false;
712     for (auto t : types)
713       {
714 	if (!found
715 	    && (reinterpret_cast<uintptr_t>(t)
716 		== reinterpret_cast<uintptr_t>(type)))
717 	  {
718 	    found = true;
719 	    continue;
720 	  }
721 	else if (found)
722 	  t->priv_->set_depends_on_recursive_type(type);
723       }
724     return found;
725   }
726 
727   /// In the stack of the current types being compared (as part of
728   /// type canonicalization), mark all the types that comes after a
729   /// certain one as NOT being eligible to the canonical type
730   /// propagation optimization.
731   ///
732   /// For a starter, please read about the @ref
733   /// OnTheFlyCanonicalization, aka, "canonical type propagation
734   /// optimization".
735   ///
736   /// To implement that optimization, we need, among other things to
737   /// maintain stack of the types (and their sub-types) being
738   /// currently compared as part of type canonicalization.
739   ///
740   /// Note that we only consider the type that is the right-hand-side
741   /// operand of the comparison because it's that one that is being
742   /// canonicalized and thus, that is not yet canonicalized.
743   ///
744   /// The reason why a type is deemed NON-eligible to the canonical
745   /// type propagation optimization is that it "depends" on
746   /// recursively present type.  Let me explain.
747   ///
748   /// Suppose we have a type T that has sub-types named ST0 and ST1.
749   /// Suppose ST1 itself has a sub-type that is T itself.  In this
750   /// case, we say that T is a recursive type, because it has T
751   /// (itself) as one of its sub-types:
752   ///
753   ///   T
754   ///   +-- ST0
755   ///   |
756   ///   +-- ST1
757   ///        +
758   ///        |
759   ///        +-- T
760   ///
761   /// ST1 is said to "depend" on T because it has T as a sub-type.
762   /// But because T is recursive, then ST1 is said to depend on a
763   /// recursive type.  Notice however that ST0 does not depend on any
764   /// recursive type.
765   ///
766   /// When we are at the point of comparing the sub-type T of ST1
767   /// against its counterpart, the stack of the right-hand-side
768   /// operands of the type canonicalization is going to look like
769   /// this:
770   ///
771   ///    | T | ST1 |
772   ///
773   /// We don't add the type T to the stack as we detect that T was
774   /// already in there (recursive cycle).
775   ///
776   /// So, this function will basically mark ST1 as being NON-eligible
777   /// to being the target of canonical type propagation.
778   ///
779   /// @param right the right-hand-side operand of the type comparison.
780   ///
781   /// @return true iff the operation was successful.
782   bool
mark_dependant_types_compared_untilpriv783   mark_dependant_types_compared_until(const type_base* right)
784   {
785     bool result = false;
786 
787     result |=
788       mark_dependant_types(right,
789 			   right_type_comp_operands_);
790     recursive_types_.insert(reinterpret_cast<uintptr_t>(right));
791     return result;
792   }
793 
794   /// Test if a type is a recursive one.
795   ///
796   /// @param t the type to consider.
797   ///
798   /// @return true iff @p t is recursive.
799   bool
is_recursive_typepriv800   is_recursive_type(const type_base* t)
801   {
802     return (recursive_types_.find(reinterpret_cast<uintptr_t>(t))
803 	    != recursive_types_.end());
804   }
805 
806 
807   /// Unflag a type as being recursive
808   ///
809   /// @param t the type to unflag
810   void
set_is_not_recursivepriv811   set_is_not_recursive(const type_base* t)
812   {recursive_types_.erase(reinterpret_cast<uintptr_t>(t));}
813 
814   /// Propagate the canonical type of a type to another one.
815   ///
816   /// @param src the type to propagate the canonical type from.
817   ///
818   /// @param dest the type to propagate the canonical type of @p src
819   /// to.
820   ///
821   /// @return bool iff the canonical was propagated.
822   bool
propagate_ctpriv823   propagate_ct(const type_base& src, const type_base& dest)
824   {
825     type_base_sptr canonical = src.get_canonical_type();
826     ABG_ASSERT(canonical);
827     dest.priv_->canonical_type = canonical;
828     dest.priv_->naked_canonical_type = canonical.get();
829     dest.priv_->set_canonical_type_propagated(true);
830     return true;
831   }
832 
833   /// Mark a set of types that have been the target of canonical type
834   /// propagation and that depend on a recursive type as being
835   /// permanently canonicalized.
836   ///
837   /// To understand the sentence above, please read the description of
838   /// type canonicalization and especially about the "canonical type
839   /// propagation optimization" at @ref OnTheFlyCanonicalization, in
840   /// the src/abg-ir.cc file.
841   void
confirm_ct_propagation_for_types_dependant_onpriv842   confirm_ct_propagation_for_types_dependant_on(const type_base* dependant_type)
843   {
844     pointer_set to_remove;
845     for (auto i : types_with_non_confirmed_propagated_ct_)
846       {
847 	type_base *t = reinterpret_cast<type_base*>(i);
848 	ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
849 		   || t->priv_->depends_on_recursive_type());
850 	t->priv_->set_does_not_depend_on_recursive_type(dependant_type);
851 	if (!t->priv_->depends_on_recursive_type())
852 	  {
853 	    to_remove.insert(i);
854 	    t->priv_->set_propagated_canonical_type_confirmed(true);
855 	  }
856       }
857 
858     for (auto i : to_remove)
859       types_with_non_confirmed_propagated_ct_.erase(i);
860   }
861 
862   /// Mark a type that has been the target of canonical type
863   /// propagation as being permanently canonicalized.
864   ///
865   /// This function also marks the set of types that have been the
866   /// target of canonical type propagation and that depend on a
867   /// recursive type as being permanently canonicalized.
868   ///
869   /// To understand the sentence above, please read the description of
870   /// type canonicalization and especially about the "canonical type
871   /// propagation optimization" at @ref OnTheFlyCanonicalization, in
872   /// the src/abg-ir.cc file.
873   void
confirm_ct_propagationpriv874   confirm_ct_propagation(const type_base*t)
875   {
876     if (!t || t->priv_->propagated_canonical_type_confirmed())
877       return;
878 
879     const environment& env = t->get_environment();
880 
881     env.priv_->confirm_ct_propagation_for_types_dependant_on(t);
882     t->priv_->set_does_not_depend_on_recursive_type();
883     env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
884     env.priv_->set_is_not_recursive(t);
885     t->priv_->set_propagated_canonical_type_confirmed(true);
886   }
887 
888   /// Mark all the types that have been the target of canonical type
889   /// propagation and that are not yet confirmed as being permanently
890   /// canonicalized (aka confirmed).
891   ///
892   /// To understand the sentence above, please read the description of
893   /// type canonicalization and especially about the "canonical type
894   /// propagation optimization" at @ref OnTheFlyCanonicalization, in
895   /// the src/abg-ir.cc file.
896   void
confirm_ct_propagationpriv897   confirm_ct_propagation()
898   {
899     for (auto i : types_with_non_confirmed_propagated_ct_)
900       {
901 	type_base *t = reinterpret_cast<type_base*>(i);
902 	ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
903 		   || t->priv_->depends_on_recursive_type());
904 	t->priv_->set_does_not_depend_on_recursive_type();
905 	t->priv_->set_propagated_canonical_type_confirmed(true);
906       }
907     types_with_non_confirmed_propagated_ct_.clear();
908   }
909 
910   /// Collect the types that depends on a given "target" type.
911   ///
912   /// Walk a set of types and if they depend directly or indirectly on
913   /// a "target" type, then collect them into a set.
914   ///
915   /// @param target the target type to consider.
916   ///
917   /// @param types the types to walk to detect those who depend on @p
918   /// target.
919   ///
920   /// @return true iff one or more type from @p types is found to
921   /// depend on @p target.
922   bool
collect_types_that_depends_onpriv923   collect_types_that_depends_on(const type_base *target,
924 				const pointer_set& types,
925 				pointer_set& collected)
926   {
927     bool result = false;
928     for (const auto i : types)
929       {
930 	// First avoid infinite loop if we've already collected the
931 	// current type.
932 	if (collected.find(i) != collected.end())
933 	  continue;
934 
935 	type_base *t = reinterpret_cast<type_base*>(i);
936 	if (t->priv_->depends_on_recursive_type(target))
937 	  {
938 	    collected.insert(i);
939 	    collect_types_that_depends_on(t, types, collected);
940 	    result = true;
941 	  }
942       }
943     return result;
944   }
945 
946   /// Reset the canonical type (set it nullptr) of a set of types that
947   /// have been the target of canonical type propagation and that
948   /// depend on a given recursive type.
949   ///
950   /// Once the canonical type of a type in that set is reset, the type
951   /// is marked as being non-dependant on a recursive type anymore.
952   ///
953   /// To understand the sentences above, please read the description
954   /// of type canonicalization and especially about the "canonical
955   /// type propagation optimization" at @ref OnTheFlyCanonicalization,
956   /// in the src/abg-ir.cc file.
957   ///
958   /// @param target if a type which has been subject to the canonical
959   /// type propagation optimizationdepends on a this target type, then
960   /// cancel its canonical type.
961   void
cancel_ct_propagation_for_types_dependant_onpriv962   cancel_ct_propagation_for_types_dependant_on(const type_base* target)
963   {
964     pointer_set to_remove;
965     collect_types_that_depends_on(target,
966 				  types_with_non_confirmed_propagated_ct_,
967 				  to_remove);
968 
969     for (auto i : to_remove)
970       {
971 	type_base *t = reinterpret_cast<type_base*>(i);
972 	ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
973 		   || t->priv_->depends_on_recursive_type());
974 	type_base_sptr canonical = t->priv_->canonical_type.lock();
975 	if (canonical)
976 	  {
977 	    t->priv_->clear_propagated_canonical_type();
978 	    t->priv_->set_does_not_depend_on_recursive_type();
979 	  }
980       }
981 
982     for (auto i : to_remove)
983       types_with_non_confirmed_propagated_ct_.erase(i);
984   }
985 
986   /// Reset the canonical type (set it nullptr) of a type that has
987   /// been the target of canonical type propagation.
988   ///
989   /// This also resets the propagated canonical type of the set of
990   /// types that depends on a given recursive type.
991   ///
992   /// Once the canonical type of a type in that set is reset, the type
993   /// is marked as being non-dependant on a recursive type anymore.
994   ///
995   /// To understand the sentences above, please read the description
996   /// of type canonicalization and especially about the "canonical
997   /// type propagation optimization" at @ref OnTheFlyCanonicalization,
998   /// in the src/abg-ir.cc file.
999   ///
1000   /// @param target if a type which has been subject to the canonical
1001   /// type propagation optimizationdepends on a this target type, then
1002   /// cancel its canonical type.
1003   void
cancel_ct_propagationpriv1004   cancel_ct_propagation(const type_base* t)
1005   {
1006     if (!t)
1007       return;
1008 
1009     const environment& env = t->get_environment();
1010     env.priv_->cancel_ct_propagation_for_types_dependant_on(t);
1011     if (t->priv_->depends_on_recursive_type()
1012 	|| env.priv_->is_recursive_type(t))
1013       {
1014 	// This cannot carry any tentative canonical type at this
1015 	// point.
1016 	if (t->priv_->canonical_type_propagated()
1017 	    && !t->priv_->propagated_canonical_type_confirmed())
1018 	  t->priv_->clear_propagated_canonical_type();
1019 	// Reset the marking of the type as it no longer carries a
1020 	// tentative canonical type that might be later cancelled.
1021 	t->priv_->set_does_not_depend_on_recursive_type();
1022 	env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
1023       }
1024   }
1025 
1026   /// Add a given type to the set of types that have been
1027   /// non-confirmed subjects of the canonical type propagation
1028   /// optimization.
1029   ///
1030   /// @param t the dependant type to consider.
1031   void
add_to_types_with_non_confirmed_propagated_ctpriv1032   add_to_types_with_non_confirmed_propagated_ct(const type_base *t)
1033   {
1034     uintptr_t v = reinterpret_cast<uintptr_t>(t);
1035     types_with_non_confirmed_propagated_ct_.insert(v);
1036   }
1037 
1038   /// Remove a given type from the set of types that have been
1039   /// non-confirmed subjects of the canonical type propagation
1040   /// optimization.
1041   ///
1042   /// @param dependant the dependant type to consider.
1043   void
remove_from_types_with_non_confirmed_propagated_ctpriv1044   remove_from_types_with_non_confirmed_propagated_ct(const type_base* dependant)
1045   {
1046     uintptr_t i = reinterpret_cast<uintptr_t>(dependant);
1047     types_with_non_confirmed_propagated_ct_.erase(i);
1048   }
1049 
1050 #ifdef WITH_DEBUG_SELF_COMPARISON
1051   /// When debugging self comparison, verify that a type T
1052   /// de-serialized from abixml has the same canonical type as the
1053   /// initial type built from DWARF that was serialized into T in the
1054   /// first place.
1055   ///
1056   /// @param t deserialized type (from abixml) to consider.
1057   ///
1058   /// @param c the canonical type @p t should have.
1059   ///
1060   /// @return true iff @p c is the canonical type that @p t should
1061   /// have.
1062   bool
check_canonical_type_from_abixml_during_self_comppriv1063   check_canonical_type_from_abixml_during_self_comp(const type_base* t,
1064 						    const type_base* c)
1065   {
1066     if (!t || !t->get_corpus() || !c)
1067       return false;
1068 
1069     if (!(t->get_corpus()->get_origin() == ir::corpus::NATIVE_XML_ORIGIN))
1070       return false;
1071 
1072     // Get the abixml type-id that this type was constructed from.
1073     string type_id;
1074     {
1075       unordered_map<uintptr_t, string>::const_iterator it =
1076 	pointer_type_id_map_.find(reinterpret_cast<uintptr_t>(t));
1077       if (it == pointer_type_id_map_.end())
1078 	// This type didn't have a type-id in the abixml file.  Maybe
1079 	// it's a function or method type.  So let's just keep going.
1080 	return true;
1081       type_id = it->second;
1082     }
1083 
1084     // Get the canonical type the original in-memory type (constructed
1085     // from DWARF) had when it was serialized into abixml in the first place.
1086     type_base *original_canonical_type = nullptr;
1087     if (!type_id.empty())
1088       {
1089 	unordered_map<string, uintptr_t>::const_iterator it =
1090 	  type_id_canonical_type_map_.find(type_id);
1091 	if (it == type_id_canonical_type_map_.end())
1092 	  return false;
1093 	original_canonical_type = reinterpret_cast<type_base*>(it->second);
1094       }
1095 
1096     // Now perform the real check.
1097     //
1098     // We want to ensure that the canonical type 'c' of 't' is the
1099     // same as the canonical type of initial in-memory type (built
1100     // from DWARF) that was serialized into 't' (in abixml) in the
1101     // first place.
1102     if (original_canonical_type == c)
1103       return true;
1104 
1105     return false;
1106   }
1107 
1108   /// When debugging self comparison, verify that a type T
1109   /// de-serialized from abixml has the same canonical type as the
1110   /// initial type built from DWARF that was serialized into T in the
1111   /// first place.
1112   ///
1113   /// @param t deserialized type (from abixml) to consider.
1114   ///
1115   /// @param c the canonical type @p t should have.
1116   ///
1117   /// @return true iff @p c is the canonical type that @p t should
1118   /// have.
1119   bool
check_canonical_type_from_abixml_during_self_comppriv1120   check_canonical_type_from_abixml_during_self_comp(const type_base_sptr& t,
1121 						    const type_base_sptr& c)
1122   {
1123     return check_canonical_type_from_abixml_during_self_comp(t.get(), c.get());
1124   }
1125 #endif
1126 };// end struct environment::priv
1127 
1128 // <class_or_union::priv definitions>
1129 struct class_or_union::priv
1130 {
1131   typedef_decl_wptr		naming_typedef_;
1132   data_members			data_members_;
1133   data_members			non_static_data_members_;
1134   member_functions		member_functions_;
1135   // A map that associates a linkage name to a member function.
1136   string_mem_fn_sptr_map_type	mem_fns_map_;
1137   // A map that associates function signature strings to member
1138   // function.
1139   string_mem_fn_ptr_map_type	signature_2_mem_fn_map_;
1140   member_function_templates	member_function_templates_;
1141   member_class_templates	member_class_templates_;
1142 
privpriv1143   priv()
1144   {}
1145 
privpriv1146   priv(class_or_union::data_members& data_mbrs,
1147        class_or_union::member_functions& mbr_fns)
1148     : data_members_(data_mbrs),
1149       member_functions_(mbr_fns)
1150   {
1151     for (data_members::const_iterator i = data_members_.begin();
1152 	 i != data_members_.end();
1153 	 ++i)
1154       if (!get_member_is_static(*i))
1155 	non_static_data_members_.push_back(*i);
1156   }
1157 
1158   /// Mark a pair of classes or unions as being currently compared
1159   /// using the class_or_union== operator.
1160   ///
1161   /// Note that this marking business is to avoid infinite loop when
1162   /// comparing a pair of classes or unions. If via the comparison of
1163   /// a data member or a member function a recursive re-comparison of
1164   /// the class or union is attempted, the marking process helps to
1165   /// detect that infinite loop possibility and avoid it.
1166   ///
1167   /// @param first the class or union (of the pair) to mark as being
1168   /// currently compared.
1169   ///
1170   /// @param second the second class or union (of the pair) to mark as
1171   /// being currently compared.
1172   void
mark_as_being_comparedpriv1173   mark_as_being_compared(const class_or_union& first,
1174 			 const class_or_union& second) const
1175   {
1176     const environment& env = first.get_environment();
1177     env.priv_->classes_being_compared_.insert
1178       (std::make_pair(reinterpret_cast<uint64_t>(&first),
1179 		      reinterpret_cast<uint64_t>(&second)));
1180   }
1181 
1182   /// Mark a pair of classes or unions as being currently compared
1183   /// using the class_or_union== operator.
1184   ///
1185   /// Note that this marking business is to avoid infinite loop when
1186   /// comparing a pair of classes or unions. If via the comparison of
1187   /// a data member or a member function a recursive re-comparison of
1188   /// the class or union is attempted, the marking process helps to
1189   /// detect that infinite loop possibility and avoid it.
1190   ///
1191   /// @param first the class or union (of the pair) to mark as being
1192   /// currently compared.
1193   ///
1194   /// @param second the second class or union (of the pair) to mark as
1195   /// being currently compared.
1196   void
mark_as_being_comparedpriv1197   mark_as_being_compared(const class_or_union* first,
1198 			 const class_or_union* second) const
1199   {mark_as_being_compared(*first, *second);}
1200 
1201   /// Mark a pair of classes or unions as being currently compared
1202   /// using the class_or_union== operator.
1203   ///
1204   /// Note that this marking business is to avoid infinite loop when
1205   /// comparing a pair of classes or unions. If via the comparison of
1206   /// a data member or a member function a recursive re-comparison of
1207   /// the class or union is attempted, the marking process helps to
1208   /// detect that infinite loop possibility and avoid it.
1209   ///
1210   /// @param first the class or union (of the pair) to mark as being
1211   /// currently compared.
1212   ///
1213   /// @param second the second class or union (of the pair) to mark as
1214   /// being currently compared.
1215   void
mark_as_being_comparedpriv1216   mark_as_being_compared(const class_or_union_sptr& first,
1217 			 const class_or_union_sptr& second) const
1218   {mark_as_being_compared(*first, *second);}
1219 
1220   /// If a pair of class_or_union has been previously marked as
1221   /// being compared -- via an invocation of mark_as_being_compared()
1222   /// this method unmarks it.  Otherwise is has no effect.
1223   ///
1224   /// This method is not thread safe because it uses the static data
1225   /// member classes_being_compared_.  If you wish to use it in a
1226   /// multi-threaded environment you should probably protect the
1227   /// access to that static data member with a mutex or somesuch.
1228   ///
1229   /// @param first the first instance of class_or_union (of the pair)
1230   /// to unmark.
1231   ///
1232   /// @param second the second instance of class_or_union (of the
1233   /// pair) to unmark.
1234   void
unmark_as_being_comparedpriv1235   unmark_as_being_compared(const class_or_union& first,
1236 			   const class_or_union& second) const
1237   {
1238     const environment& env = first.get_environment();
1239     env.priv_->classes_being_compared_.erase
1240       (std::make_pair(reinterpret_cast<uint64_t>(&first),
1241 		      reinterpret_cast<uint64_t>(&second)));
1242   }
1243 
1244   /// If a pair of class_or_union has been previously marked as
1245   /// being compared -- via an invocation of mark_as_being_compared()
1246   /// this method unmarks it.  Otherwise is has no effect.
1247   ///
1248   /// This method is not thread safe because it uses the static data
1249   /// member classes_being_compared_.  If you wish to use it in a
1250   /// multi-threaded environment you should probably protect the
1251   /// access to that static data member with a mutex or somesuch.
1252   ///
1253   /// @param first the first instance of class_or_union (of the pair)
1254   /// to unmark.
1255   ///
1256   /// @param second the second instance of class_or_union (of the
1257   /// pair) to unmark.
1258   void
unmark_as_being_comparedpriv1259   unmark_as_being_compared(const class_or_union* first,
1260 			   const class_or_union* second) const
1261   {
1262     if (!first || !second)
1263       return;
1264     unmark_as_being_compared(*first, *second);
1265   }
1266 
1267   /// Test if a pair of class_or_union is being currently compared.
1268   ///
1269   ///@param first the first class or union (of the pair) to test for.
1270   ///
1271   ///@param second the second class or union (of the pair) to test for.
1272   ///
1273   /// @return true if the pair {@p first, @p second} is being
1274   /// compared, false otherwise.
1275   bool
comparison_startedpriv1276   comparison_started(const class_or_union& first,
1277 		     const class_or_union& second) const
1278   {
1279     const environment& env = first.get_environment();
1280     return env.priv_->
1281       classes_being_compared_.count
1282       (std::make_pair(reinterpret_cast<uint64_t>(&first),
1283 		      reinterpret_cast<uint64_t>((&second))));
1284   }
1285 
1286   /// Test if a pair of class_or_union is being currently compared.
1287   ///
1288   ///@param first the first class or union (of the pair) to test for.
1289   ///
1290   ///@param second the second class or union (of the pair) to test for.
1291   ///
1292   /// @return true if the pair {@p first, @p second} is being
1293   /// compared, false otherwise.
1294   bool
comparison_startedpriv1295   comparison_started(const class_or_union* first,
1296 		     const class_or_union* second) const
1297   {
1298     if (first && second)
1299       return comparison_started(*first, *second);
1300     return false;
1301   }
1302 }; // end struct class_or_union::priv
1303 
1304 // <function_type::priv definitions>
1305 
1306 /// The type of the private data of the @ref function_type type.
1307 struct function_type::priv
1308 {
1309   parameters parms_;
1310   type_base_wptr return_type_;
1311   interned_string cached_name_;
1312   interned_string internal_cached_name_;
1313   interned_string temp_internal_cached_name_;
1314 
privpriv1315   priv()
1316   {}
1317 
privpriv1318   priv(const parameters&	parms,
1319        type_base_sptr		return_type)
1320     : parms_(parms),
1321       return_type_(return_type)
1322   {}
1323 
privpriv1324   priv(type_base_sptr return_type)
1325     : return_type_(return_type)
1326   {}
1327 
1328   /// Mark a given pair of @ref function_type as being compared.
1329   ///
1330   /// @param first the first @ref function_type of the pair being
1331   /// compared, to mark.
1332   ///
1333   /// @param second the second @ref function_type of the pair being
1334   /// compared, to mark.
1335   void
mark_as_being_comparedpriv1336   mark_as_being_compared(const function_type& first,
1337 			 const function_type& second) const
1338   {
1339     const environment& env = first.get_environment();
1340     env.priv_->fn_types_being_compared_.insert
1341       (std::make_pair(reinterpret_cast<uint64_t>(&first),
1342 		      reinterpret_cast<uint64_t>(&second)));
1343   }
1344 
1345   /// Mark a given pair of @ref function_type as being compared.
1346   ///
1347   /// @param first the first @ref function_type of the pair being
1348   /// compared, to mark.
1349   ///
1350   /// @param second the second @ref function_type of the pair being
1351   /// compared, to mark.
1352   void
unmark_as_being_comparedpriv1353   unmark_as_being_compared(const function_type& first,
1354 			   const function_type& second) const
1355   {
1356     const environment& env = first.get_environment();
1357     env.priv_->fn_types_being_compared_.erase
1358       (std::make_pair(reinterpret_cast<uint64_t>(&first),
1359 		      reinterpret_cast<uint64_t>(&second)));
1360   }
1361 
1362   /// Tests if a @ref function_type is currently being compared.
1363   ///
1364   /// @param type the function type to take into account.
1365   ///
1366   /// @return true if @p type is being compared.
1367   bool
comparison_startedpriv1368   comparison_started(const function_type& first,
1369 		     const function_type& second) const
1370   {
1371     const environment& env = first.get_environment();
1372     return env.priv_->fn_types_being_compared_.count
1373       (std::make_pair(reinterpret_cast<uint64_t>(&first),
1374 		      reinterpret_cast<uint64_t>(&second)));
1375   }
1376 };// end struc function_type::priv
1377 
1378 // </function_type::priv definitions>
1379 
1380 } // end namespace ir
1381 
1382 } // end namespace abigail
1383 
1384 #endif // __ABG_IR_PRIV_H__
1385