public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Add incomplete enum support.
@ 2020-06-10 11:59 Giuliano Procida
  2020-06-10 11:59 ` [PATCH 01/11] Missing initialisation of source local variable Giuliano Procida
                   ` (11 more replies)
  0 siblings, 12 replies; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

Hi. This is my latest iteration of incomplete enum support. I think
more help is needed for abg-reader.cc.

Mirror: https://github.com/myxoid/libabigail/commits/incomplete-enums.

Dodji Seketeli (2):
  Add invariant to enum_type_decl::set_is_declaration_only
  Support constructing opaque types for enums

Giuliano Procida (9):
  Missing initialisation of source local variable.
  Improve code comments and whitespace.
  Refactor d.context() as ctxt in report(enum_diff).
  Tidy build_enum_type state variables.
  Rename declaration-definition change category.
  Support incomplete enums in core and diff code.
  Support declaration-only enums in DWARF reader.
  Add declaration-only enums to XML reader/writer.
  Add tests for declaration-only enums.

 include/abg-comp-filter.h                     |   7 +
 include/abg-comparison.h                      |  10 +-
 include/abg-fwd.h                             |  26 +-
 include/abg-ir.h                              |  15 +
 src/abg-comp-filter.cc                        |  80 +++-
 src/abg-comparison.cc                         |  18 +-
 src/abg-default-reporter.cc                   |  32 +-
 src/abg-dwarf-reader.cc                       | 390 ++++++++++++++++--
 src/abg-ir.cc                                 | 200 ++++++++-
 src/abg-leaf-reporter.cc                      |   2 +-
 src/abg-reader.cc                             |   4 +
 src/abg-writer.cc                             |  17 +
 tests/data/Makefile.am                        |   5 +
 .../test-decl-enum-report.txt                 |  17 +
 .../test-abidiff-exit/test-decl-enum-v0.c     |   5 +
 .../test-abidiff-exit/test-decl-enum-v0.o     | Bin 0 -> 3048 bytes
 .../test-abidiff-exit/test-decl-enum-v1.c     |   5 +
 .../test-abidiff-exit/test-decl-enum-v1.o     | Bin 0 -> 3048 bytes
 tests/test-abidiff-exit.cc                    |   9 +
 19 files changed, 775 insertions(+), 67 deletions(-)
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-report.txt
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.c
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.c
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.o

-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 01/11] Missing initialisation of source local variable.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-06-10 11:59 ` [PATCH 02/11] Improve code comments and whitespace Giuliano Procida
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

This will be fixed by maennich, one way or another.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-dwarf-reader.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 77af0441..1218f8c7 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -3190,7 +3190,7 @@ public:
 		    size_t where,
 		    bool die_as_type) const
   {
-    die_source source;
+    die_source source = NO_DEBUG_INFO_DIE_SOURCE;
     ABG_ASSERT(get_die_source(die, source));
 
     offset_offset_map_type &canonical_dies =
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 02/11] Improve code comments and whitespace.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
  2020-06-10 11:59 ` [PATCH 01/11] Missing initialisation of source local variable Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-06-29  8:26   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 03/11] Refactor d.context() as ctxt in report(enum_diff) Giuliano Procida
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

These are zero impact changes.

	* include/abg-fwd.h: Correct doc-comment reference to
	enum_type_decl.
	* src/abg-comp-filter.cc: Fix doc-comment syntax.
	* src/abg-comparison.cc (operator<<): In the diff_category
	overload, fix code indentation.
	* src/abg-default-reporter.cc (report): In the
	class_or_union_diff overload, adjust comment to reflect that
	the code is reporting changes between declaration-only and
	defined types, in either direction.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 include/abg-fwd.h           | 2 +-
 src/abg-comp-filter.cc      | 4 ++--
 src/abg-comparison.cc       | 8 ++++----
 src/abg-default-reporter.cc | 2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index f6e0c5b2..999b071b 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -152,7 +152,7 @@ typedef weak_ptr<typedef_decl> typedef_decl_wptr;
 
 class enum_type_decl;
 
-/// Convenience typedef for shared pointer on enum_type_decl.
+/// Convenience typedef for shared pointer to a @ref enum_type_decl.
 typedef shared_ptr<enum_type_decl> enum_type_decl_sptr;
 
 class class_or_union;
diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
index 67c2a180..36fca73d 100644
--- a/src/abg-comp-filter.cc
+++ b/src/abg-comp-filter.cc
@@ -961,8 +961,8 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
 /// other one is defined.
 ///
 /// @param diff the diff node to consider.
-////
-//// @return true if the class_or_union_diff carries a change in which
+///
+/// @return true if the class_or_union_diff carries a change in which
 /// the two classes are different by the fact that one is a decl-only
 /// and the other one is defined.
 bool
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index 7305a71a..857ffa8a 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -3132,7 +3132,7 @@ operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
-    if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
+  if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
     {
       if (emitted_a_category)
 	o << "|";
@@ -3140,7 +3140,7 @@ operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
-   if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
+  if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
     {
       if (emitted_a_category)
 	o << "|";
@@ -3148,7 +3148,7 @@ operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
-    if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
+  if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
     {
       if (emitted_a_category)
 	o << "|";
@@ -3156,7 +3156,7 @@ operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
-    if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
+  if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
     {
       if (emitted_a_category)
 	o << "|";
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 80cb6638..7c98d8d7 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -844,7 +844,7 @@ default_reporter::report(const class_or_union_diff& d,
 
   const diff_context_sptr& ctxt = d.context();
 
-  // Report class decl-only -> definition change.
+  // Report class decl-only <-> definition change.
   if (ctxt->get_allowed_category() & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY)
     if (filtering::has_class_decl_only_def_change(first, second))
       {
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 03/11] Refactor d.context() as ctxt in report(enum_diff).
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
  2020-06-10 11:59 ` [PATCH 01/11] Missing initialisation of source local variable Giuliano Procida
  2020-06-10 11:59 ` [PATCH 02/11] Improve code comments and whitespace Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-06-29  8:54   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 04/11] Tidy build_enum_type state variables Giuliano Procida
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

	* src/abg-default-reporter.cc (report): In the enum_diff
	overload, introduce the name ctxt to replace four occurrences
	of d.context().

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-default-reporter.cc | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 7c98d8d7..42851346 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -98,9 +98,10 @@ default_reporter::report(const enum_diff& d, ostream& out,
 
   enum_type_decl_sptr first = d.first_enum(), second = d.second_enum();
 
-  report_name_size_and_alignment_changes(first, second, d.context(),
+  const diff_context_sptr& ctxt = d.context();
+  report_name_size_and_alignment_changes(first, second, ctxt,
 					 out, indent);
-  maybe_report_diff_for_member(first, second, d.context(), out, indent);
+  maybe_report_diff_for_member(first, second, ctxt, out, indent);
 
   //underlying type
   d.underlying_type_diff()->report(out, indent);
@@ -165,12 +166,12 @@ default_reporter::report(const enum_diff& d, ostream& out,
 	      << "' from value '"
 	      << i->first.get_value() << "' to '"
 	      << i->second.get_value() << "'";
-	  report_loc_info(second, *d.context(), out);
+	  report_loc_info(second, *ctxt, out);
 	  out << "\n";
 	}
     }
 
-  if (d.context()->show_leaf_changes_only())
+  if (ctxt->show_leaf_changes_only())
     maybe_report_interfaces_impacted_by_diff(&d, out, indent);
 
   d.reported_once(true);
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 04/11] Tidy build_enum_type state variables.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (2 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 03/11] Refactor d.context() as ctxt in report(enum_diff) Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-06-29  9:08   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 05/11] Rename declaration-definition change category Giuliano Procida
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

This patch brings the enum code closer to the class/union code, in the
hope that this will ease future code maintenance.

There are no behavioural changes.

	* src/abg-dwarf-reader.cc (build_enum_type): Rename local
	variable enum_is_anonymous to is_anonymous. Move initilisation
	of local variable is_artificial to location corresponding to
	that in add_or_update_class_type and add_or_update_union_type
	functions.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-dwarf-reader.cc | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 1218f8c7..9b3e6371 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -13284,14 +13284,14 @@ build_enum_type(read_context&	ctxt,
   location loc;
   die_loc_and_name(ctxt, die, loc, name, linkage_name);
 
-  bool enum_is_anonymous = false;
+  bool is_anonymous = false;
   // If the enum is anonymous, let's give it a name.
   if (name.empty())
     {
       name = get_internal_anonymous_die_prefix_name(die);
       ABG_ASSERT(!name.empty());
       // But we remember that the type is anonymous.
-      enum_is_anonymous = true;
+      is_anonymous = true;
 
       if (size_t s = scope->get_num_anonymous_member_enums())
 	name = build_internal_anonymous_die_name(name, s);
@@ -13303,7 +13303,7 @@ build_enum_type(read_context&	ctxt,
   // representation (name) and location can be later detected as being
   // for the same type.
 
-  if (!enum_is_anonymous)
+  if (!is_anonymous)
     {
       if (use_odr)
 	{
@@ -13336,6 +13336,7 @@ build_enum_type(read_context&	ctxt,
   uint64_t size = 0;
   if (die_unsigned_constant_attribute(die, DW_AT_byte_size, size))
     size *= 8;
+  bool is_artificial = die_is_artificial(die);
 
   // for now we consider that underlying types of enums are all anonymous
   bool enum_underlying_type_is_anonymous= true;
@@ -13368,8 +13369,6 @@ build_enum_type(read_context&	ctxt,
       while (dwarf_siblingof(&child, &child) == 0);
     }
 
-  bool is_artificial = die_is_artificial(die);
-
   // DWARF up to version 4 (at least) doesn't seem to carry the
   // underlying type, so let's create an artificial one here, which
   // sole purpose is to be passed to the constructor of the
@@ -13385,7 +13384,7 @@ build_enum_type(read_context&	ctxt,
   t = dynamic_pointer_cast<type_decl>(d);
   ABG_ASSERT(t);
   result.reset(new enum_type_decl(name, loc, t, enms, linkage_name));
-  result->set_is_anonymous(enum_is_anonymous);
+  result->set_is_anonymous(is_anonymous);
   result->set_is_artificial(is_artificial);
   ctxt.associate_die_to_type(die, result, where_offset);
   return result;
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 05/11] Rename declaration-definition change category.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (3 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 04/11] Tidy build_enum_type state variables Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-06-29 16:17   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 06/11] Support incomplete enums in core and diff code Giuliano Procida
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

This patch renames CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY to
TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 include/abg-comparison.h    | 10 +++++-----
 src/abg-comp-filter.cc      |  2 +-
 src/abg-comparison.cc       |  6 +++---
 src/abg-default-reporter.cc |  2 +-
 src/abg-leaf-reporter.cc    |  2 +-
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/abg-comparison.h b/include/abg-comparison.h
index bb510a18..a46c7184 100644
--- a/include/abg-comparison.h
+++ b/include/abg-comparison.h
@@ -418,10 +418,9 @@ enum diff_category
   /// present as a child of a other nodes in the diff tree.
   REDUNDANT_CATEGORY = 1 << 13,
 
-  /// This means that a diff node in the sub-tree carries a class type
-  /// that was declaration-only and that is now defined, or vice
-  /// versa.
-  CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14,
+  /// This means that a diff node in the sub-tree carries a type that
+  /// was declaration-only and that is now defined, or vice versa.
+  TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14,
 
   /// A diff node in this category is a function parameter type which
   /// top cv-qualifiers change.
@@ -447,6 +446,7 @@ enum diff_category
   /// array type of a global variable, but the ELF size of the
   /// variable didn't change.
   BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 20,
+
   /// A special enumerator that is the logical 'or' all the
   /// enumerators above.
   ///
@@ -467,7 +467,7 @@ enum diff_category
   | SIZE_OR_OFFSET_CHANGE_CATEGORY
   | VIRTUAL_MEMBER_CHANGE_CATEGORY
   | REDUNDANT_CATEGORY
-  | CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY
+  | TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
   | FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
   | FN_PARM_TYPE_CV_CHANGE_CATEGORY
   | FN_RETURN_TYPE_CV_CHANGE_CATEGORY
diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
index 36fca73d..81548427 100644
--- a/src/abg-comp-filter.cc
+++ b/src/abg-comp-filter.cc
@@ -1518,7 +1518,7 @@ categorize_harmless_diff_node(diff *d, bool pre)
 	s = is_decl(d->second_subject());
 
       if (has_class_decl_only_def_change(d))
-	category |= CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY;
+	category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY;
 
       if (access_changed(f, s))
 	category |= ACCESS_CHANGE_CATEGORY;
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index 857ffa8a..f77799f2 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -2957,7 +2957,7 @@ get_default_harmless_categories_bitmap()
 	  | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY
 	  | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
 	  | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
-	  | abigail::comparison::CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY
+	  | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
 	  | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
 	  | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
 	  | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
@@ -3108,11 +3108,11 @@ operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
-  if (c & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY)
+  if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
     {
       if (emitted_a_category)
 	o << "|";
-      o << "CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY";
+      o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
       emitted_a_category |= true;
     }
 
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 42851346..2acb6954 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -846,7 +846,7 @@ default_reporter::report(const class_or_union_diff& d,
   const diff_context_sptr& ctxt = d.context();
 
   // Report class decl-only <-> definition change.
-  if (ctxt->get_allowed_category() & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY)
+  if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
     if (filtering::has_class_decl_only_def_change(first, second))
       {
 	string was =
diff --git a/src/abg-leaf-reporter.cc b/src/abg-leaf-reporter.cc
index f9d905ab..37d0fde3 100644
--- a/src/abg-leaf-reporter.cc
+++ b/src/abg-leaf-reporter.cc
@@ -461,7 +461,7 @@ leaf_reporter::report(const class_or_union_diff& d,
   const diff_context_sptr& ctxt = d.context();
 
   // Report class decl-only -> definition change.
-  if (ctxt->get_allowed_category() & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY)
+  if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
     if (filtering::has_class_decl_only_def_change(first, second))
       {
 	string was =
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 06/11] Support incomplete enums in core and diff code.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (4 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 05/11] Rename declaration-definition change category Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-07-06 11:14   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 07/11] Add invariant to enum_type_decl::set_is_declaration_only Giuliano Procida
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

This is an almost blind attempt at addition of support for incomplete,
also known as forward-declared, enum types. I've not made any attempt
to refactor or share logic with the struct/union code and I've
probably got other things wrong.

This patch:

- adds enums_type and enum_type_decl_wptr typedefs
- adds declaration-only machinery to enum_type_decl
- adds is_compatible_with_enum_type, look_through_decl_only_class,
  there_is_a_decl_only_enum and lookup_enum_type helpers
- adds has_enum_decl_only_def_change functions
- inserts has_enum_decl_only_def_change wherever
  has_class_decl_only_def_change is present
- adds reporting of enum declaration/definition diffs
- doesn't address the DWARF reader, XML writer or XML reader

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 include/abg-comp-filter.h   |   7 ++
 include/abg-fwd.h           |  24 +++++
 include/abg-ir.h            |  15 +++
 src/abg-comp-filter.cc      |  74 +++++++++++++-
 src/abg-comparison.cc       |   4 +-
 src/abg-default-reporter.cc |  19 ++++
 src/abg-ir.cc               | 196 +++++++++++++++++++++++++++++++++++-
 7 files changed, 333 insertions(+), 6 deletions(-)

diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h
index 81130033..3b845088 100644
--- a/include/abg-comp-filter.h
+++ b/include/abg-comp-filter.h
@@ -68,9 +68,16 @@ bool
 has_class_decl_only_def_change(const class_or_union_sptr& first,
 			       const class_or_union_sptr& second);
 
+bool
+has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
+			      const enum_type_decl_sptr& second);
+
 bool
 has_class_decl_only_def_change(const diff *diff);
 
+bool
+has_enum_decl_only_def_change(const diff *diff);
+
 bool
 has_basic_type_name_change(const diff *);
 
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 999b071b..73d809ab 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -155,6 +155,12 @@ class enum_type_decl;
 /// Convenience typedef for shared pointer to a @ref enum_type_decl.
 typedef shared_ptr<enum_type_decl> enum_type_decl_sptr;
 
+/// Convenience typedef for a vector of @ref enum_type_decl_sptr
+typedef vector<enum_type_decl_sptr> enums_type;
+
+/// Convenience typedef for a weak pointer to a @ref enum_type_decl.
+typedef weak_ptr<enum_type_decl> enum_type_decl_wptr;
+
 class class_or_union;
 
 typedef shared_ptr<class_or_union> class_or_union_sptr;
@@ -423,6 +429,12 @@ is_typedef(const type_base*);
 typedef_decl*
 is_typedef(type_base*);
 
+enum_type_decl_sptr
+is_compatible_with_enum_type(const type_base_sptr&);
+
+enum_type_decl_sptr
+is_compatible_with_enum_type(const decl_base_sptr&);
+
 enum_type_decl_sptr
 is_enum_type(const type_or_decl_base_sptr&);
 
@@ -513,6 +525,12 @@ look_through_decl_only_class(const class_or_union&);
 class_or_union_sptr
 look_through_decl_only_class(class_or_union_sptr);
 
+enum_type_decl_sptr
+look_through_decl_only_enum(const enum_type_decl&);
+
+enum_type_decl_sptr
+look_through_decl_only_enum(enum_type_decl_sptr);
+
 var_decl*
 is_var_decl(const type_or_decl_base*);
 
@@ -1085,6 +1103,12 @@ lookup_enum_type(const string&, const corpus&);
 enum_type_decl_sptr
 lookup_enum_type(const interned_string&, const corpus&);
 
+const type_base_wptrs_type*
+lookup_enum_types(const interned_string&, const corpus&);
+
+const type_base_wptrs_type*
+lookup_enum_types(const string&, const corpus&);
+
 enum_type_decl_sptr
 lookup_enum_type_per_location(const interned_string&, const corpus&);
 
diff --git a/include/abg-ir.h b/include/abg-ir.h
index ebcc4b81..2114e27b 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -2497,6 +2497,21 @@ public:
   enumerators&
   get_enumerators();
 
+  bool
+  get_is_declaration_only() const;
+
+  void
+  set_is_declaration_only(bool f);
+
+  void
+  set_definition_of_declaration(enum_type_decl_sptr);
+
+  const enum_type_decl_sptr
+  get_definition_of_declaration() const;
+
+  const enum_type_decl*
+  get_naked_definition_of_declaration() const;
+
   virtual string
   get_pretty_representation(bool internal = false,
 			    bool qualified_name = true) const;
diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
index 81548427..70858f27 100644
--- a/src/abg-comp-filter.cc
+++ b/src/abg-comp-filter.cc
@@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1,
   return false;
 }
 
+/// Test if there is a enum that is declaration-only among the two
+/// enums in parameter.
+///
+/// @param enum1 the first enum to consider.
+///
+/// @param enum2 the second enum to consider.
+///
+/// @return true if either enums are declaration-only, false
+/// otherwise.
+static bool
+there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1,
+			  const enum_type_decl_sptr& enum2)
+{
+  if ((enum1 && enum1->get_is_declaration_only())
+      || (enum2 && enum2->get_is_declaration_only()))
+    return true;
+  return false;
+}
+
 /// Test if the diff involves a declaration-only class.
 ///
 /// @param diff the class diff to consider.
@@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s)
       || f->get_size_in_bits() == 0
       || s->get_size_in_bits() == 0
       || there_is_a_decl_only_class(is_compatible_with_class_type(f),
-				    is_compatible_with_class_type(s)))
+				    is_compatible_with_class_type(s))
+      || there_is_a_decl_only_enum(is_compatible_with_enum_type(f),
+				   is_compatible_with_enum_type(s)))
     return false;
 
   return f->get_size_in_bits() != s->get_size_in_bits();
@@ -956,6 +977,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
   return (f->get_is_declaration_only() != s->get_is_declaration_only());
 }
 
+/// Test if two @ref enum_sptr are different just by the
+/// fact that one is decl-only and the other one is defined.
+///
+/// @param first the first enum to consider.
+///
+/// @param second the second enum to consider.
+///
+/// @return true iff the two arguments are different just by the fact
+/// that one is decl-only and the other one is defined.
+bool
+has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
+			      const enum_type_decl_sptr& second)
+{
+  if (!first || !second)
+    return false;
+
+  enum_type_decl_sptr f = look_through_decl_only_enum(first);
+  enum_type_decl_sptr s = look_through_decl_only_enum(second);
+
+  if (f->get_qualified_name() != s->get_qualified_name())
+    return false;
+
+  return (f->get_is_declaration_only() != s->get_is_declaration_only());
+}
+
 /// Test if a class_or_union_diff carries a change in which the two
 /// classes are different by the fact that one is a decl-only and the
 /// other one is defined.
@@ -980,6 +1026,28 @@ has_class_decl_only_def_change(const diff *diff)
   return has_class_decl_only_def_change(f, s);
 }
 
+/// Test if a enum_diff carries a change in which the two enums are
+/// different by the fact that one is a decl-only and the other one is
+/// defined.
+///
+/// @param diff the diff node to consider.
+///
+/// @return true if the enum_diff carries a change in which the two
+/// enums are different by the fact that one is a decl-only and the
+/// other one is defined.
+bool
+has_enum_decl_only_def_change(const diff *diff)
+{
+  const enum_diff *d = dynamic_cast<const enum_diff*>(diff);
+  if (!d)
+    return false;
+
+  enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum());
+  enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum());
+
+  return has_enum_decl_only_def_change(f, s);
+}
+
 /// Test if a diff node carries a basic type name change.
 ///
 /// @param d the diff node to consider.
@@ -1517,7 +1585,8 @@ categorize_harmless_diff_node(diff *d, bool pre)
       decl_base_sptr f = is_decl(d->first_subject()),
 	s = is_decl(d->second_subject());
 
-      if (has_class_decl_only_def_change(d))
+      if (has_class_decl_only_def_change(d)
+	  || has_enum_decl_only_def_change(d))
 	category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY;
 
       if (access_changed(f, s))
@@ -1608,6 +1677,7 @@ categorize_harmful_diff_node(diff *d, bool pre)
       //
       // TODO: be more specific -- not all size changes are harmful.
       if (!has_class_decl_only_def_change(d)
+	  && !has_enum_decl_only_def_change(d)
 	  && (type_size_changed(f, s)
 	      || data_member_offset_changed(f, s)
 	      || non_static_data_member_type_size_changed(f, s)
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index f77799f2..21cab0e7 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -10962,7 +10962,9 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor
 	// with the is_declaration flag set) that carries a non-zero
 	// size!  And of course at some point that non-zero size
 	// changes.  We need to be able to detect that.
-	&& !filtering::is_decl_only_class_with_size_change(d))
+	&& !filtering::is_decl_only_class_with_size_change(d)
+	// Don't show decl-only-ness changes of enums.
+	&& !filtering::has_enum_decl_only_def_change(d))
       {
 	diff_context_sptr ctxt = d->context();
 	const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 2acb6954..cbf8c2bc 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out,
   enum_type_decl_sptr first = d.first_enum(), second = d.second_enum();
 
   const diff_context_sptr& ctxt = d.context();
+
+  // Report enum decl-only <-> definition changes.
+  if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
+    if (filtering::has_enum_decl_only_def_change(first, second))
+      {
+	string was =
+	  first->get_is_declaration_only()
+	  ? " was a declaration-only enum type"
+	  : " was a defined enum type";
+
+	string is_now =
+	  second->get_is_declaration_only()
+	  ? " and is now a declaration-only enum type"
+	  : " and is now a defined enum type";
+
+	out << indent << "enum type " << name << was << is_now << "\n";
+	return;
+      }
+
   report_name_size_and_alignment_changes(first, second, ctxt,
 					 out, indent);
   maybe_report_diff_for_member(first, second, ctxt, out, indent);
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 5cc39f59..9f4890e8 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -7924,6 +7924,38 @@ typedef_decl*
 is_typedef(type_base* t)
 {return dynamic_cast<typedef_decl*>(t);}
 
+/// Test if a type is a enum. This function looks through typedefs.
+///
+/// @parm t the type to consider.
+///
+/// @return the enum_decl if @p t is a enum_decl or null otherwise.
+enum_type_decl_sptr
+is_compatible_with_enum_type(const type_base_sptr& t)
+{
+  if (!t)
+    return enum_type_decl_sptr();
+
+  // Normally we should strip typedefs entirely, but this is
+  // potentially costly, especially on binaries with huge changesets
+  // like the Linux Kernel.  So we just get the leaf types for now.
+  //
+  // Maybe there should be an option by which users accepts to pay the
+  // CPU usage toll in exchange for finer filtering?
+
+  // type_base_sptr ty = strip_typedef(t);
+  type_base_sptr ty = peel_typedef_type(t);;
+  return is_enum_type(ty);
+}
+
+/// Test if a type is a enum. This function looks through typedefs.
+///
+/// @parm t the type to consider.
+///
+/// @return the enum_decl if @p t is a enum_decl or null otherwise.
+enum_type_decl_sptr
+is_compatible_with_enum_type(const decl_base_sptr& t)
+{return is_compatible_with_enum_type(is_type(t));}
+
 /// Test if a decl is an enum_type_decl
 ///
 /// @param d the decl to test for.
@@ -8307,6 +8339,50 @@ look_through_decl_only_class(class_or_union_sptr klass)
   return result;
 }
 
+/// If a enum is a decl-only enum, get its definition.
+/// Otherwise, just return the initial enum.
+///
+/// @param the_enum the enum to consider.
+///
+/// @return either the definition of the enum, or the enum itself.
+enum_type_decl_sptr
+look_through_decl_only_enum(const enum_type_decl& the_enum)
+{
+  enum_type_decl_sptr enom;
+  if (the_enum.get_is_declaration_only())
+    enom = the_enum.get_definition_of_declaration();
+
+  if (!enom)
+    return enom;
+
+  while (enom
+	 && enom->get_is_declaration_only()
+	 && enom->get_definition_of_declaration())
+    enom = enom->get_definition_of_declaration();
+
+  ABG_ASSERT(enom);
+  return enom;
+}
+
+/// If a enum is a decl-only enum, get its definition.
+/// Otherwise, just return the initial enum.
+///
+/// @param enom the enum to consider.
+///
+/// @return either the definition of the enum, or the enum itself.
+enum_type_decl_sptr
+look_through_decl_only_enum(enum_type_decl_sptr enom)
+{
+  if (!enom)
+    return enom;
+
+  enum_type_decl_sptr result = look_through_decl_only_enum(*enom);
+  if (!result)
+    result = enom;
+
+  return result;
+}
+
 /// Tests if a declaration is a variable declaration.
 ///
 /// @param decl the decl to test.
@@ -10165,6 +10241,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp)
   return result;
 }
 
+/// Look into a given corpus to find the enum type*s* that have a
+/// given qualified name.
+///
+/// @param qualified_name the qualified name of the type to look for.
+///
+/// @param corp the corpus to look into.
+///
+/// @return the vector of enum types that which name is @p qualified_name.
+const type_base_wptrs_type *
+lookup_enum_types(const interned_string& qualified_name, const corpus& corp)
+{
+  const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types();
+
+  return lookup_types_in_map(qualified_name, m);
+}
+
+/// Look into a given corpus to find the enum type*s* that have a
+/// given qualified name.
+///
+/// @param qualified_name the qualified name of the type to look for.
+///
+/// @param corp the corpus to look into.
+///
+/// @return the vector of enum types that which name is @p qualified_name.
+const type_base_wptrs_type*
+lookup_enum_types(const string& qualified_name, const corpus& corp)
+{
+  interned_string s = corp.get_environment()->intern(qualified_name);
+  return lookup_enum_types(s, corp);
+}
+
 /// Look up an @ref enum_type_decl from a given corpus, by its location.
 ///
 /// @param loc the location to consider.
@@ -14974,17 +15081,26 @@ class enum_type_decl::priv
 {
   type_base_sptr	underlying_type_;
   enumerators		enumerators_;
+  decl_base_sptr       	declaration_;
+  enum_type_decl_wptr	definition_of_declaration_;
+  enum_type_decl*	naked_definition_of_declaration_;
+  bool			is_declaration_only_;
 
   friend class enum_type_decl;
 
-  priv();
-
 public:
 
+  priv()
+    : naked_definition_of_declaration_(),
+      is_declaration_only_(true)
+  {}
+
   priv(type_base_sptr underlying_type,
        enumerators& enumerators)
     : underlying_type_(underlying_type),
-      enumerators_(enumerators)
+      enumerators_(enumerators),
+      naked_definition_of_declaration_(),
+      is_declaration_only_(false)
   {}
 }; // end class enum_type_decl::priv
 
@@ -15040,6 +15156,80 @@ enum_type_decl::enumerators&
 enum_type_decl::get_enumerators()
 {return priv_->enumerators_;}
 
+/// Set the definition of this declaration-only @ref enum_type_decl.
+///
+/// @param d the new definition to set.
+void
+enum_type_decl::set_definition_of_declaration(enum_type_decl_sptr d)
+{
+  ABG_ASSERT(get_is_declaration_only());
+  priv_->definition_of_declaration_ = d;
+  if (d->get_canonical_type())
+    type_base::priv_->canonical_type = d->get_canonical_type();
+
+  priv_->naked_definition_of_declaration_ = d.get();
+}
+
+/// If this @ref enum_type_decl_sptr is declaration-only, get its
+/// definition, if any.
+///
+/// @return the definition of this decl-only enum.
+const enum_type_decl_sptr
+enum_type_decl::get_definition_of_declaration() const
+{
+  if (priv_->definition_of_declaration_.expired())
+    return enum_type_decl_sptr();
+  return enum_type_decl_sptr(priv_->definition_of_declaration_);
+}
+
+///  If this @ref enum_type_decl is declaration-only, get its
+///  definition, if any.
+///
+/// Note that this function doesn't return a smart pointer, but rather
+/// the underlying pointer managed by the smart pointer.  So it's as
+/// fast as possible.  This getter is to be used in code paths that are
+/// proven to be performance hot spots; especially, when comparing
+/// sensitive types like enums.  Those are compared extremely frequently
+/// and thus, their access to the definition of declaration must be
+/// fast.
+///
+/// @return the definition of the enum.
+const enum_type_decl*
+enum_type_decl::get_naked_definition_of_declaration() const
+{return priv_->naked_definition_of_declaration_;}
+
+/// Test if a @ref enum_type_decl is a declaration-only @ref
+/// enum_type_decl.
+///
+/// @return true iff the current @ref enum_type_decl is a
+/// declaration-only @ref enum_type_decl.
+bool
+enum_type_decl::get_is_declaration_only() const
+{return priv_->is_declaration_only_;}
+
+/// Set a flag saying if the @ref enum_type_decl is a declaration-only
+/// @ref enum_type_decl.
+///
+/// @param f true if the @ref enum_type_decl is a decalaration-only
+/// @ref enum_type_decl.
+void
+enum_type_decl::set_is_declaration_only(bool f)
+{
+  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
+
+  priv_->is_declaration_only_ = f;
+
+  if (update_types_lookup_map)
+    if (scope_decl* s = get_scope())
+      {
+	scope_decl::declarations::iterator i;
+	if (s->find_iterator_for_member(this, i))
+	  maybe_update_types_lookup_map(*i);
+	else
+	  ABG_ASSERT_NOT_REACHED;
+      }
+}
+
 /// Get the pretty representation of the current instance of @ref
 /// enum_type_decl.
 ///
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 07/11] Add invariant to enum_type_decl::set_is_declaration_only
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (5 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 06/11] Support incomplete enums in core and diff code Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-07-06 11:15   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 08/11] Support declaration-only enums in DWARF reader Giuliano Procida
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida, Dodji Seketeli

From: Dodji Seketeli <dodji@redhat.com>

A declaration-only enum can't have enumerators, so let's enact that
invariant.

	* src/abg-ir.cc (enum_type_decl::set_is_declaration_only): assert
	that a declaration-only enum can't have enumerator.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-ir.cc | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 9f4890e8..4aaf3cca 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -15228,6 +15228,10 @@ enum_type_decl::set_is_declaration_only(bool f)
 	else
 	  ABG_ASSERT_NOT_REACHED;
       }
+
+  // A decl-only enum can't have enumerators.
+  if (priv_->is_declaration_only_ && !get_enumerators().empty())
+    ABG_ASSERT_NOT_REACHED;
 }
 
 /// Get the pretty representation of the current instance of @ref
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 08/11] Support declaration-only enums in DWARF reader.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (6 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 07/11] Add invariant to enum_type_decl::set_is_declaration_only Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-07-06 11:22   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 09/11] Support constructing opaque types for enums Giuliano Procida
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

This patch adds declaration-only handling enums to the DWARF reader,
except for support in get_opaque_version_of_type.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-dwarf-reader.cc | 238 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 237 insertions(+), 1 deletion(-)

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 9b3e6371..fddfb149 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -198,6 +198,10 @@ typedef unordered_map<Dwarf_Off, Dwarf_Off> offset_offset_map_type;
 /// value is a vector of smart pointer to a class.
 typedef unordered_map<string, classes_type> string_classes_map;
 
+/// Convenience typedef for a map which key is a string and which
+/// value is a vector of smart pointer to a enum.
+typedef unordered_map<string, enums_type> string_enums_map;
+
 /// The abstraction of the place where a partial unit has been
 /// imported.  This is what the DW_TAG_imported_unit DIE expresses.
 ///
@@ -2282,6 +2286,7 @@ public:
   vector<Dwarf_Off>		type_unit_types_to_canonicalize_;
   vector<type_base_sptr>	extra_types_to_canonicalize_;
   string_classes_map		decl_only_classes_map_;
+  string_enums_map		decl_only_enums_map_;
   die_tu_map_type		die_tu_map_;
   corpus_group_sptr		cur_corpus_group_;
   corpus_sptr			cur_corpus_;
@@ -4621,6 +4626,203 @@ public:
       }
   }
 
+  /// Getter for the map of declaration-only enums that are to be
+  /// resolved to their definition enums by the end of the corpus
+  /// loading.
+  ///
+  /// @return a map of string -> vector of enums where the key is
+  /// the fully qualified name of the enum and the value is the
+  /// vector of declaration-only enum.
+  const string_enums_map&
+  declaration_only_enums() const
+  {return decl_only_enums_map_;}
+
+  /// Getter for the map of declaration-only enums that are to be
+  /// resolved to their definition enums by the end of the corpus
+  /// loading.
+  ///
+  /// @return a map of string -> vector of enums where the key is
+  /// the fully qualified name of the enum and the value is the
+  /// vector of declaration-only enum.
+  string_enums_map&
+  declaration_only_enums()
+  {return decl_only_enums_map_;}
+
+  /// If a given enum is a declaration-only enum then stash it on
+  /// the side so that at the end of the corpus reading we can resolve
+  /// it to its definition.
+  ///
+  /// @param enom the enum to consider.
+  void
+  maybe_schedule_declaration_only_enum_for_resolution(enum_type_decl_sptr& enom)
+  {
+    if (enom->get_is_declaration_only()
+	&& enom->get_definition_of_declaration() == 0)
+      {
+	string qn = enom->get_qualified_name();
+	string_enums_map::iterator record =
+	  declaration_only_enums().find(qn);
+	if (record == declaration_only_enums().end())
+	  declaration_only_enums()[qn].push_back(enom);
+	else
+	  record->second.push_back(enom);
+      }
+  }
+
+  /// Test if a given declaration-only enum has been scheduled for
+  /// resolution to a defined enum.
+  ///
+  /// @param enom the enum to consider for the test.
+  ///
+  /// @return true iff @p enom is a declaration-only enum and if
+  /// it's been scheduled for resolution to a defined enum.
+  bool
+  is_decl_only_enum_scheduled_for_resolution(enum_type_decl_sptr& enom)
+  {
+    if (enom->get_is_declaration_only())
+      return (declaration_only_enums().find(enom->get_qualified_name())
+	      != declaration_only_enums().end());
+
+    return false;
+  }
+
+  /// Walk the declaration-only enums that have been found during
+  /// the building of the corpus and resolve them to their definitions.
+  void
+  resolve_declaration_only_enums()
+  {
+    vector<string> resolved_enums;
+
+    for (string_enums_map::iterator i =
+	   declaration_only_enums().begin();
+	 i != declaration_only_enums().end();
+	 ++i)
+      {
+	bool to_resolve = false;
+	for (enums_type::iterator j = i->second.begin();
+	     j != i->second.end();
+	     ++j)
+	  if ((*j)->get_is_declaration_only()
+	      && ((*j)->get_definition_of_declaration() == 0))
+	    to_resolve = true;
+
+	if (!to_resolve)
+	  {
+	    resolved_enums.push_back(i->first);
+	    continue;
+	  }
+
+	// Now, for each decl-only enum that have the current name
+	// 'i->first', let's try to poke at the fully defined enum
+	// that is defined in the same translation unit as the
+	// declaration.
+	//
+	// If we find one enum (defined in the TU of the declaration)
+	// that defines the declaration, then the declaration can be
+	// resolved to that enum.
+	//
+	// If no defining enum is found in the TU of the declaration,
+	// then there are possibly three cases to consider:
+	//
+	//   1/ There is exactly one enum that defines the
+	//   declaration and that enum is defined in another TU.  In
+	//   this case, the declaration is resolved to that
+	//   definition.
+	//
+	//   2/ There are more than one enum that define that
+	//   declaration and none of them is defined in the TU of the
+	//   declaration.  In this case, the declaration is left
+	//   unresolved.
+	//
+	//   3/ No enum defines the declaration.  In this case, the
+	//   declaration is left unresoved.
+
+	// So get the enums that might define the current
+	// declarations which name is i->first.
+	const type_base_wptrs_type *enums =
+	  lookup_enum_types(i->first, *current_corpus());
+	if (!enums)
+	  continue;
+
+	unordered_map<string, enum_type_decl_sptr> per_tu_enum_map;
+	for (type_base_wptrs_type::const_iterator c = enums->begin();
+	     c != enums->end();
+	     ++c)
+	  {
+	    enum_type_decl_sptr enom = is_enum_type(type_base_sptr(*c));
+	    ABG_ASSERT(enom);
+
+	    enom = is_enum_type(look_through_decl_only_enum(enom));
+	    if (enom->get_is_declaration_only())
+	      continue;
+
+	    string tu_path = enom->get_translation_unit()->get_absolute_path();
+	    if (tu_path.empty())
+	      continue;
+
+	    // Build a map that associates the translation unit path
+	    // to the enum (that potentially defines the declarations
+	    // that we consider) that are defined in that translation unit.
+	    per_tu_enum_map[tu_path] = enom;
+	  }
+
+	if (!per_tu_enum_map.empty())
+	  {
+	    // Walk the declarations to resolve and resolve them
+	    // either to the definitions that are in the same TU as
+	    // the declaration, or to the definition found elsewhere,
+	    // if there is only one such definition.
+	    for (enums_type::iterator j = i->second.begin();
+		 j != i->second.end();
+		 ++j)
+	      {
+		if ((*j)->get_is_declaration_only()
+		    && ((*j)->get_definition_of_declaration() == 0))
+		  {
+		    string tu_path =
+		      (*j)->get_translation_unit()->get_absolute_path();
+		    unordered_map<string, enum_type_decl_sptr>::const_iterator e =
+		      per_tu_enum_map.find(tu_path);
+		    if (e != per_tu_enum_map.end())
+		      (*j)->set_definition_of_declaration(e->second);
+		    else if (per_tu_enum_map.size() == 1)
+		      (*j)->set_definition_of_declaration
+			(per_tu_enum_map.begin()->second);
+		  }
+	      }
+	    resolved_enums.push_back(i->first);
+	  }
+      }
+
+    size_t num_decl_only_enums = declaration_only_enums().size(),
+      num_resolved = resolved_enums.size();
+    if (show_stats())
+      cerr << "resolved " << num_resolved
+	   << " enum declarations out of "
+	   << num_decl_only_enums
+	   << "\n";
+
+    for (vector<string>::const_iterator i = resolved_enums.begin();
+	 i != resolved_enums.end();
+	 ++i)
+      declaration_only_enums().erase(*i);
+
+    for (string_enums_map::iterator i = declaration_only_enums().begin();
+	 i != declaration_only_enums().end();
+	 ++i)
+      {
+	if (show_stats())
+	  {
+	    if (i == declaration_only_enums().begin())
+	      cerr << "Here are the "
+		   << num_decl_only_enums - num_resolved
+		   << " unresolved enum declarations:\n";
+	    else
+	      cerr << "    " << i->first << "\n";
+	  }
+      }
+  }
+
   /// Some functions described by DWARF may have their linkage name
   /// set, but no link to their actual underlying elf symbol.  When
   /// these are virtual member functions, comparing the enclosing type
@@ -13283,6 +13485,7 @@ build_enum_type(read_context&	ctxt,
   string name, linkage_name;
   location loc;
   die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  bool is_declaration_only = die_is_declaration_only(die);
 
   bool is_anonymous = false;
   // If the enum is anonymous, let's give it a name.
@@ -13385,8 +13588,12 @@ build_enum_type(read_context&	ctxt,
   ABG_ASSERT(t);
   result.reset(new enum_type_decl(name, loc, t, enms, linkage_name));
   result->set_is_anonymous(is_anonymous);
+  result->set_is_declaration_only(is_declaration_only);
   result->set_is_artificial(is_artificial);
   ctxt.associate_die_to_type(die, result, where_offset);
+
+  ctxt.maybe_schedule_declaration_only_enum_for_resolution(result);
+
   return result;
 }
 
@@ -16125,6 +16332,24 @@ read_debug_info_into_corpus(read_context& ctxt)
       }
   }
 
+  {
+    tools_utils::timer t;
+    if (ctxt.do_log())
+      {
+	cerr << "resolving declaration only enums ...";
+	t.start();
+      }
+    ctxt.resolve_declaration_only_enums();
+    if (ctxt.do_log())
+      {
+	t.stop();
+	cerr << " DONE@" << ctxt.current_corpus()->get_path()
+	     << ":"
+	     << t
+	     <<"\n";
+      }
+  }
+
   {
     tools_utils::timer t;
     if (ctxt.do_log())
@@ -16559,7 +16784,18 @@ build_ir_node_from_die(read_context&	ctxt,
 
     case DW_TAG_enumeration_type:
       {
-	if (!type_is_suppressed(ctxt, scope, die))
+	bool type_is_private = false;
+	bool type_suppressed =
+	  type_is_suppressed(ctxt, scope, die, type_is_private);
+	if (type_suppressed && type_is_private)
+	  // The type is suppressed because it's private.  If other
+	  // non-suppressed and declaration-only instances of this
+	  // type exist in the current corpus, then it means those
+	  // non-suppressed instances are opaque versions of the
+	  // suppressed private type.  Lets return one of these opaque
+	  // types then.
+	  result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
+	else if (!type_suppressed)
 	  {
 	    enum_type_decl_sptr e = build_enum_type(ctxt, die, scope,
 						    where_offset);
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 09/11] Support constructing opaque types for enums
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (7 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 08/11] Support declaration-only enums in DWARF reader Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-07-06 11:23   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 10/11] Add declaration-only enums to XML reader/writer Giuliano Procida
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida, Dodji Seketeli

From: Dodji Seketeli <dodji@redhat.com>

Now that we are to support opaque types for enums, we ought to support
building opaque types for enums as well, to mimic the opaque type
design pattern used in C, when private types are specified with type
suppression specifications.

The core of this change is to make get_opaque_version_of_type work for
enums as well, just like what it does for classes.  Note that that
function doesn't support opaque unions yet either.  That should be
added at a later point in time, I guess.

	* src/abg-dwarf-reader.cc
	(build_internal_underlying_enum_type_name)
	(build_enum_underlying_type): Factorize these functions out of ...
	(build_enum_type): ... here.
	(get_opaque_version_of_type): Make this handle enums as well.  So
	make its return type be type_or_decl_base_sptr, rather than just
	class_or_union_sptr as it used to be.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-dwarf-reader.cc | 139 +++++++++++++++++++++++++++++++---------
 1 file changed, 109 insertions(+), 30 deletions(-)

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index fddfb149..6b71c1ab 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -438,11 +438,14 @@ static string
 build_internal_anonymous_die_name(const string &base_name,
 				  size_t anonymous_type_index);
 
-
 static string
 get_internal_anonymous_die_name(Dwarf_Die *die,
 				size_t anonymous_type_index);
 
+static string
+build_internal_underlying_enum_type_name(const string &base_name,
+					 bool is_anonymous);
+
 static string
 die_qualified_type_name(const read_context& ctxt,
 			const Dwarf_Die* die,
@@ -10943,6 +10946,29 @@ build_internal_anonymous_die_name(const string &base_name,
   return name;
 }
 
+/// Build the internal name of the underlying type of an enum.
+///
+/// @param base_name the (unqualified) name of the enum the underlying
+/// type is destined to.
+///
+/// @param is_anonymous true if the underlying type of the enum is to
+/// be anonymous.
+static string
+build_internal_underlying_enum_type_name(const string &base_name,
+					 bool is_anonymous = true)
+{
+  std::ostringstream o;
+
+  if (is_anonymous)
+    o << "unnamed-enum";
+  else
+    o << "enum-" << base_name;
+
+  o << "-underlying-type";
+
+  return o.str();
+}
+
 /// Build a full internal anonymous type name.
 ///
 /// @param die the DIE representing the anonymous type to consider.
@@ -13457,6 +13483,39 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
   return result;
 }
 
+/// Construct the type that is to be used as the underlying type of an
+/// enum.
+///
+/// @param ctxt the read context to use.
+///
+/// @param enum_name the name of the enum that this type is going to
+/// be the underlying type of.
+///
+/// @param enum_size the size of the enum.
+///
+/// @param is_anonymous whether the underlying type is anonymous or
+/// not. By default, this should be set to true as before c++11 (and
+/// in C), it's almost the case.
+static type_decl_sptr
+build_enum_underlying_type(read_context& ctxt,
+			   string enum_name,
+			   uint64_t enum_size,
+			   bool is_anonymous = true)
+{
+  string underlying_type_name =
+    build_internal_underlying_enum_type_name(enum_name, is_anonymous);
+
+  type_decl_sptr result(new type_decl(ctxt.env(), underlying_type_name,
+				      enum_size, enum_size, location()));
+  result->set_is_anonymous(is_anonymous);
+  translation_unit_sptr tu = ctxt.cur_transl_unit();
+  decl_base_sptr d = add_decl_to_scope(result, tu->get_global_scope().get());
+  result = dynamic_pointer_cast<type_decl>(d);
+  ABG_ASSERT(result);
+  canonicalize(result);
+  return result;
+}
+
 /// Build an enum_type_decl from a DW_TAG_enumeration_type DIE.
 ///
 /// @param ctxt the read context to use.
@@ -13543,15 +13602,6 @@ build_enum_type(read_context&	ctxt,
 
   // for now we consider that underlying types of enums are all anonymous
   bool enum_underlying_type_is_anonymous= true;
-  string underlying_type_name;
-  if (enum_underlying_type_is_anonymous)
-    {
-      underlying_type_name = "unnamed-enum";
-      enum_underlying_type_is_anonymous = true;
-    }
-  else
-    underlying_type_name = string("enum-") + name;
-  underlying_type_name += "-underlying-type";
 
   enum_type_decl::enumerators enms;
   Dwarf_Die child;
@@ -13576,16 +13626,10 @@ build_enum_type(read_context&	ctxt,
   // underlying type, so let's create an artificial one here, which
   // sole purpose is to be passed to the constructor of the
   // enum_type_decl type.
-  type_decl_sptr t(new type_decl(ctxt.env(), underlying_type_name,
-				 size, size, location()));
-  t->set_is_anonymous(enum_underlying_type_is_anonymous);
-  translation_unit_sptr tu = ctxt.cur_transl_unit();
-  decl_base_sptr d =
-    add_decl_to_scope(t, tu->get_global_scope().get());
-  canonicalize(t);
+  type_decl_sptr t =
+    build_enum_underlying_type(ctxt, name, size,
+			       enum_underlying_type_is_anonymous);
 
-  t = dynamic_pointer_cast<type_decl>(d);
-  ABG_ASSERT(t);
   result.reset(new enum_type_decl(name, loc, t, enms, linkage_name));
   result->set_is_anonymous(is_anonymous);
   result->set_is_declaration_only(is_declaration_only);
@@ -15858,7 +15902,8 @@ type_is_suppressed(const read_context& ctxt,
 /// a private type.
 ///
 /// The opaque version version of the type is just a declared-only
-/// version of the type (class or union type) denoted by @p type_die.
+/// version of the type (class, union or enum type) denoted by @p
+/// type_die.
 ///
 /// @param ctxt the read context in use.
 ///
@@ -15873,13 +15918,13 @@ type_is_suppressed(const read_context& ctxt,
 ///
 /// @return the opaque version of the type denoted by @p type_die or
 /// nil if no opaque version was found.
-static class_or_union_sptr
+static type_or_decl_base_sptr
 get_opaque_version_of_type(read_context	&ctxt,
 			   scope_decl		*scope,
 			   Dwarf_Die		*type_die,
 			   size_t		where_offset)
 {
-  class_or_union_sptr result;
+  type_or_decl_base_sptr result;
 
   if (type_die == 0)
     return result;
@@ -15887,7 +15932,14 @@ get_opaque_version_of_type(read_context	&ctxt,
   unsigned tag = dwarf_tag(type_die);
   if (tag != DW_TAG_class_type
       && tag != DW_TAG_structure_type
-      && tag != DW_TAG_union_type)
+      && tag != DW_TAG_union_type
+      && tag != DW_TAG_enumeration_type)
+    return result;
+
+  if (tag == DW_TAG_union_type)
+    // TODO: also handle declaration-only unions.  To do that, we mostly
+    // need to adapt add_or_update_union_type to make it schedule
+    // declaration-only unions for resolution too.
     return result;
 
   string type_name, linkage_name;
@@ -15898,17 +15950,19 @@ get_opaque_version_of_type(read_context	&ctxt,
 
   string qualified_name = build_qualified_name(scope, type_name);
 
+  //
   // TODO: also handle declaration-only unions.  To do that, we mostly
   // need to adapt add_or_update_union_type to make it schedule
   // declaration-only unions for resolution too.
-  string_classes_map::const_iterator i =
-    ctxt.declaration_only_classes().find(qualified_name);
-  if (i != ctxt.declaration_only_classes().end())
-    result = i->second.back();
-
-  if (!result)
+  //
+  if (tag == DW_TAG_structure_type || tag == DW_TAG_class_type)
     {
-      if (tag == DW_TAG_class_type || tag == DW_TAG_structure_type)
+      string_classes_map::const_iterator i =
+	ctxt.declaration_only_classes().find(qualified_name);
+      if (i != ctxt.declaration_only_classes().end())
+	result = i->second.back();
+
+      if (!result)
 	{
 	  // So we didn't find any pre-existing forward-declared-only
 	  // class for the class definition that we could return as an
@@ -15928,6 +15982,31 @@ get_opaque_version_of_type(read_context	&ctxt,
 	}
     }
 
+  if (tag == DW_TAG_enumeration_type)
+    {
+      string_enums_map::const_iterator i =
+	ctxt.declaration_only_enums().find(qualified_name);
+      if (i != ctxt.declaration_only_enums().end())
+	result = i->second.back();
+
+      if (!result)
+	{
+	  uint64_t size = 0;
+	  if (die_unsigned_constant_attribute(type_die, DW_AT_byte_size, size))
+	    size *= 8;
+	  type_decl_sptr underlying_type =
+	    build_enum_underlying_type(ctxt, type_name, size,
+				       /*anonymous=*/true);
+	  enum_type_decl::enumerators enumeratorz;
+	  enum_type_decl_sptr enum_type (new enum_type_decl(type_name,
+							    type_location,
+							    underlying_type,
+							    enumeratorz,
+							    linkage_name));
+	  result = enum_type;
+	}
+    }
+
   return result;
 }
 
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (8 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 09/11] Support constructing opaque types for enums Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-07-02 13:55   ` Dodji Seketeli
  2020-07-06 11:31   ` Dodji Seketeli
  2020-06-10 11:59 ` [PATCH 11/11] Add tests for declaration-only enums Giuliano Procida
  2020-07-01 13:36 ` [PATCH 00/11] Add incomplete enum support Dodji Seketeli
  11 siblings, 2 replies; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

Serialisation seems OK.

Deserialisation quite likely needs declaration/definition resolution
as there is logic for this for class types.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-reader.cc |  4 ++++
 src/abg-writer.cc | 17 +++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/src/abg-reader.cc b/src/abg-reader.cc
index eb74659f..62eda332 100644
--- a/src/abg-reader.cc
+++ b/src/abg-reader.cc
@@ -4161,6 +4161,9 @@ build_enum_type_decl(read_context&	ctxt,
   location loc;
   read_location(ctxt, node, loc);
 
+  bool is_decl_only = false;
+  read_is_declaration_only(node, is_decl_only);
+
   bool is_anonymous = false;
   read_is_anonymous(node, is_anonymous);
 
@@ -4221,6 +4224,7 @@ build_enum_type_decl(read_context&	ctxt,
 					   enums, linkage_name));
   t->set_is_anonymous(is_anonymous);
   t->set_is_artificial(is_artificial);
+  t->set_is_declaration_only(is_decl_only); // TODO: more to do here!
   if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
     {
       ctxt.map_xml_node_to_decl(node, t);
diff --git a/src/abg-writer.cc b/src/abg-writer.cc
index bafa3024..38320867 100644
--- a/src/abg-writer.cc
+++ b/src/abg-writer.cc
@@ -840,6 +840,8 @@ static bool write_elf_symbol_reference(const elf_symbol&, ostream&);
 static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&);
 static void write_class_or_union_is_declaration_only(const class_or_union_sptr&,
 						     ostream&);
+static void write_enum_is_declaration_only(const enum_type_decl_sptr&,
+					   ostream&);
 static void write_is_struct(const class_decl_sptr&, ostream&);
 static void write_is_anonymous(const decl_base_sptr&, ostream&);
 static void write_naming_typedef(const class_decl_sptr&, write_context&);
@@ -1754,6 +1756,20 @@ write_class_or_union_is_declaration_only(const class_or_union_sptr& t,
     o << " is-declaration-only='yes'";
 }
 
+/// Serialize the attribute "is-declaration-only", if the enum has its
+/// is_declaration_only property set.
+///
+/// @param t the pointer to instance of @ref enum_type_decl to
+/// consider.
+///
+/// @param o the output stream to serialize to.
+static void
+write_enum_is_declaration_only(const enum_type_decl_sptr& t, ostream& o)
+{
+  if (t->get_is_declaration_only())
+    o << " is-declaration-only='yes'";
+}
+
 /// Serialize the attribute "is-struct", if the current instance of
 /// class_decl is a struct.
 ///
@@ -2889,6 +2905,7 @@ write_enum_type_decl(const enum_type_decl_sptr& decl,
     o << " linkage-name='" << decl->get_linkage_name() << "'";
 
   write_location(decl, ctxt);
+  write_enum_is_declaration_only(decl, o);
 
   string i = id;
   if (i.empty())
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 11/11] Add tests for declaration-only enums.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (9 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 10/11] Add declaration-only enums to XML reader/writer Giuliano Procida
@ 2020-06-10 11:59 ` Giuliano Procida
  2020-07-06 11:26   ` Dodji Seketeli
  2020-07-01 13:36 ` [PATCH 00/11] Add incomplete enum support Dodji Seketeli
  11 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-06-10 11:59 UTC (permalink / raw)
  To: libabigail; +Cc: dodji, kernel-team, gprocida

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 tests/data/Makefile.am                         |   5 +++++
 .../test-decl-enum-report.txt                  |  17 +++++++++++++++++
 .../data/test-abidiff-exit/test-decl-enum-v0.c |   5 +++++
 .../data/test-abidiff-exit/test-decl-enum-v0.o | Bin 0 -> 3048 bytes
 .../data/test-abidiff-exit/test-decl-enum-v1.c |   5 +++++
 .../data/test-abidiff-exit/test-decl-enum-v1.o | Bin 0 -> 3048 bytes
 tests/test-abidiff-exit.cc                     |   9 +++++++++
 7 files changed, 41 insertions(+)
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-report.txt
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.c
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.c
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.o

diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 6592ba32..7b239682 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -158,6 +158,11 @@ test-abidiff-exit/test-fun-param-v0.o \
 test-abidiff-exit/test-fun-param-v1.abi \
 test-abidiff-exit/test-fun-param-v1.c \
 test-abidiff-exit/test-fun-param-v1.o \
+test-abidiff-exit/test-decl-enum-v0.c \
+test-abidiff-exit/test-decl-enum-v0.o \
+test-abidiff-exit/test-decl-enum-v1.c \
+test-abidiff-exit/test-decl-enum-v1.o \
+test-abidiff-exit/test-decl-enum-report.txt \
 \
 test-diff-dwarf/test0-v0.cc		\
 test-diff-dwarf/test0-v0.o			\
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-report.txt b/tests/data/test-abidiff-exit/test-decl-enum-report.txt
new file mode 100644
index 00000000..e46ebfa6
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-report.txt
@@ -0,0 +1,17 @@
+Functions changes summary: 0 Removed, 2 Changed, 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C] 'function void reg1(const embodied_enum*)' at test-decl-enum-v1.c:4:1 has some indirect sub-type changes:
+    parameter 1 of type 'const embodied_enum*' has sub-type changes:
+      in pointed to type 'const embodied_enum':
+        in unqualified underlying type 'enum embodied_enum' at test-decl-enum-v1.c:1:1:
+          enum type enum embodied_enum was a declaration-only enum type and is now a defined enum type
+
+  [C] 'function void reg2(const disembodied_enum*)' at test-decl-enum-v1.c:5:1 has some indirect sub-type changes:
+    parameter 1 of type 'const disembodied_enum*' has sub-type changes:
+      in pointed to type 'const disembodied_enum':
+        in unqualified underlying type 'enum disembodied_enum':
+          enum type enum disembodied_enum was a defined enum type and is now a declaration-only enum type
+
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v0.c b/tests/data/test-abidiff-exit/test-decl-enum-v0.c
new file mode 100644
index 00000000..d5672618
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-v0.c
@@ -0,0 +1,5 @@
+enum embodied_enum;
+enum disembodied_enum { X };
+
+void reg1(const enum embodied_enum * foo) { (void)foo; }
+void reg2(const enum disembodied_enum * foo) { (void)foo; }
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v0.o b/tests/data/test-abidiff-exit/test-decl-enum-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..b4c0b06a089ec6adbfa81b1a619ae30087e54f9d
GIT binary patch
literal 3048
zcmbtWUuzsy6hE^wo1Hk#Hp$xBG=+{(+eDplH%QIaCa$Ko2^OhB#TN;)J2$(7+1WBP
zTT?|XqC&xk3W5lt4}JmB7hejZzU!Cp!8d&qe9&`d?%CYjOcC_J+<VUN{GEH}oZWYy
zzk0c17{Fw}I_yh~0xZ?``A*JupaJu6ee=$*n|I#+^X_XuD(v@YVdYkK9_&cYE6Z_(
zuMl6ews18nQ<rcvU&Y1paH(2(-YI0ksOB574lPK==kMTJ+Zl~eyG(rL;{n(<1u1;2
z5}$7-KGxZL(q|fXEP_<F{T&I$obgD#;h6Qs`kXOen|%m_TZUO*cN}M{alv`oX*)&(
zi(LZKK7|!oXJHHF>KSmHb@am$eB+q~vtHPqTc9wV6Q4e}KyI}vx)qwOM&$&iJ&Jx5
zVA=x8a&ZBRcpRVne88rfCZwL<1VrX4J|;Yht6}_ApTRZ1Tf77VGLdFpD0;h|h{r?k
zX4CKGuGPn2y2ydzvFh>ns{R_T6%)P3aT@hw5xP;Fff#m2VI;zB@`o@=4+2+SyzXwa
zo^sp%ir;cqnyq%L)oi=oFdN5WtuJDcL_HLPq&HaGTRrccf712(uD27Ux8mL)8O5V<
z>W$+!qB!)jpt~#5(wY;|ZvieV@I*Ge0dQqw<AS?%NpzziE|Pn#_Oez+{-(G*C>i6;
zm%-SZH5QN5?7Mh8rx2%yDF3>it<Qc~*_fHSj0T92?jk9X%JhZi@JgS*1%Lc~SVI?;
zH^(8BDX&~tnCMYPrtCFcXBIu6!x%+rW<_g4-USL$u;!%S4ysI;IS5F}1pM|($b>_4
z0FI&EymAiQ*(W8=GVlNLMNHoK0ra1=KJuKIaC%E>ETXw$1IBMlnd%~9{EI>aYDyxy
zxk=L?zf2$!*{iMU=jeW%MJZFG5^?-O0(eO>jDIF&nutW4m(Sya0-nVAM9Lq@o$aLv
z-)i=JgM3z$x5~!2&q`j8)4mVxN}SF{J)e$-bN%3_w}#m4xMxYR517luUIu;`WC8fy
zGzC8qyMZ5y?zq1l#XBR^<$TcXCgSD+b&v#cALobavKz&MT`&dsz0q(eaIX3BC=))8
zFE7o4-s{py47PWYU?^na|8t{zr!(Yp=5QU!=mVW>ReBf&!t@F7ifW|ry8k)U(RcY@
z{afg($E0+e|0fa@(ru~V=pR8xu_5*s0+Cjw1AT7<aS!1SV@_+h>M==iQi9wExp9f@
zwGxbMzm)z>5){&Ny@0y1`fYik>`(R6bk*w*5z}KL1V2lV>QhO#-9}|u{#BWu&x!KW
zeADyaK#XEG@loltY|^h(5P8ne`&$yz{eO`D^nIzse!RbrO6FC&-_#+YD0EwzgM{hk
zze|AUBZuJkXPM?=+4)^7xj*{#Vt+o@vfLDVQ#RB<7EHe<G*fkdx)Z(k5Q49%D5TTH
UHd*!er?_SQw`KkJyFU*24@%k9)Bpeg

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v1.c b/tests/data/test-abidiff-exit/test-decl-enum-v1.c
new file mode 100644
index 00000000..046a55d3
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-v1.c
@@ -0,0 +1,5 @@
+enum embodied_enum { Y };
+enum disembodied_enum;
+
+void reg1(const enum embodied_enum * foo) { (void)foo; }
+void reg2(const enum disembodied_enum * foo) { (void)foo; }
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v1.o b/tests/data/test-abidiff-exit/test-decl-enum-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..e9c8d081a21e6d3806fb79661e4fb3c333cc442d
GIT binary patch
literal 3048
zcmbtVPj4GV6o2Dg#}3=LNlZ)ARO(hLZ35jTj!=n96AUSBA}Umnir|2vwRd8#h}YHb
zx}+f53YAK^1qrFDRKbBSz!yM5z#YB>2X1gf;sEc>&e)U5_5x4ZH}C!4-}$@u-n@Rb
z#26@Ium)pIp#Te&vD^}33+gZnH#hcv+t~Z;ul)~y(!?Lo!xmmuk?e?&HFjK+OC(q9
zP2`MCT*1Nm0GaI}E8C*(1d71QVj$5WhQyxSMPAt+4A8o`hjQu59#qLxvB@-9eSka<
zw+q6*Cr=S>pCg&VC#%#0uo?Dzt?pR0`PvMdtxP|MR-0M1HOFx_>zABYou<R;*z5vW
z)l=A!eGWEJFP{a+S;IK2>$BJ9tXl4SevZ<#PCR;Jj>0Ns49hK>_0kD|stuI<@*H-3
z6jM+xxIjHoH~FN5L`+}55s1Qd{496@Ib(m<rjU!h#Z6$4@ig;7-r4bZJnVb78-7QG
zmS2R)yauYr%Ev!1`>V)H7Df-_H0s7YbfY*cOb|vX@3#kG#KSF03)kMh>8>|kahv|K
z-*A_g8qG#ysp)$CY#8&^E{}N<bx;kGPH%O0<)U}-W!LMv-gc1Qi95Yy5D$i_H;g}y
z;?T>2_6|?sV1<Nt8-Q#XUdsBn0IsdCUvd|&@OBi$d0DT~Tr?UGGe!2S6xb*40^6Nt
z^G7PxeO#VXh|@<TPS@+T>4&BDsfnxTfEd{>lM$)No?8xcI{r5N`OjesZIrkihfJ2-
za?@a8L=jo?u9-F~Klmn$S+vWnSuL2<w6SQ7?%Nn6$%3hafYdC&vtK|K9C`=f82Zg>
z>!5D-Nr@|6jfIDBd?H3Oeg@-5_Z?+bnQ)rrGJZre`2Y%6GorqT6#jLt0^UwRv~#0N
zgYsey3xDzcNZr?Ps{2stbWw>^{#*liM+ypmEcN&0sOqZqxM%pEk@~)Ye<k%ta#VSw
zI$A5LTUH>B(^5A5n@_=AiPPHX>(erD)j#;@ojzW39J3@JdrHdqZU%lBWC8f?GzCB5
zJAoha_OQDZ#oGh42{~xD6Mp-EIY@%Ii!X;BvJ=Hzg<uKrJA;0o<Gbd^gN*z5aCvDK
zbUu<nytlQT1br?W|DVG=#?u<=XOdF3h#{E|I{E5!1{K207vMeJNt4a^^Jt@U`CsE3
z7;EOFa;pB%q-bRNUO=0TUrX~L@mB(oR%8I3H-gk1!XKlcRpe$)GMtp)7s6}IOy3)5
zGBNW0MuJP@P$8MVZy{RLe^qX%il_eRbv64B5i@fl1iwg-`qRnu-9lqg{S{eXtrOL!
zcgC!L3o**Mgr82Q<t6=A2T@k_)%dBz%=jN=Je@C{RGb<gpi#-X-|sSB$4EAP=^Z4@
zbpJyF>V2eGA~pY91EBY>X#H*!>>vHTRJ>Z(qS};uLtdz!Y?%Hh^baxPX-~|%hY);6
YO(C7mhY>gDPkD>t@5}z5wtp(&zdst)dH?_b

literal 0
HcmV?d00001

diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc
index 4d9c1943..4fc1eec7 100644
--- a/tests/test-abidiff-exit.cc
+++ b/tests/test-abidiff-exit.cc
@@ -212,6 +212,15 @@ InOutSpec in_out_specs[] =
     "data/test-abidiff-exit/test-fun-param-report.txt",
     "output/test-abidiff-exit/test-fun-param-report.txt"
   },
+  {
+    "data/test-abidiff-exit/test-decl-enum-v0.o",
+    "data/test-abidiff-exit/test-decl-enum-v1.o",
+    "",
+    "--harmless",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-decl-enum-report.txt",
+    "output/test-abidiff-exit/test-decl-enum-report.txt"
+  },
   {0, 0, 0 ,0,  abigail::tools_utils::ABIDIFF_OK, 0, 0}
 };
 
-- 
2.27.0.278.ge193c7cf3a9-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 02/11] Improve code comments and whitespace.
  2020-06-10 11:59 ` [PATCH 02/11] Improve code comments and whitespace Giuliano Procida
@ 2020-06-29  8:26   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-06-29  8:26 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> These are zero impact changes.
>
> 	* include/abg-fwd.h: Correct doc-comment reference to
> 	enum_type_decl.
> 	* src/abg-comp-filter.cc: Fix doc-comment syntax.
> 	* src/abg-comparison.cc (operator<<): In the diff_category
> 	overload, fix code indentation.
> 	* src/abg-default-reporter.cc (report): In the
> 	class_or_union_diff overload, adjust comment to reflect that
> 	the code is reporting changes between declaration-only and
> 	defined types, in either direction.
>
> Signed-off-by: Giuliano Procida <gprocida@google.com>

Applied to master.  Thanks!

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 03/11] Refactor d.context() as ctxt in report(enum_diff).
  2020-06-10 11:59 ` [PATCH 03/11] Refactor d.context() as ctxt in report(enum_diff) Giuliano Procida
@ 2020-06-29  8:54   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-06-29  8:54 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> 	* src/abg-default-reporter.cc (report): In the enum_diff
> 	overload, introduce the name ctxt to replace four occurrences
> 	of d.context().
>
> Signed-off-by: Giuliano Procida <gprocida@google.com>

Applied to master, thanks!

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 04/11] Tidy build_enum_type state variables.
  2020-06-10 11:59 ` [PATCH 04/11] Tidy build_enum_type state variables Giuliano Procida
@ 2020-06-29  9:08   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-06-29  9:08 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> This patch brings the enum code closer to the class/union code, in the
> hope that this will ease future code maintenance.
>
> There are no behavioural changes.
>
> 	* src/abg-dwarf-reader.cc (build_enum_type): Rename local
> 	variable enum_is_anonymous to is_anonymous. Move initilisation
> 	of local variable is_artificial to location corresponding to
> 	that in add_or_update_class_type and add_or_update_union_type
> 	functions.
>
> Signed-off-by: Giuliano Procida <gprocida@google.com>

Applied to master, thanks!

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 05/11] Rename declaration-definition change category.
  2020-06-10 11:59 ` [PATCH 05/11] Rename declaration-definition change category Giuliano Procida
@ 2020-06-29 16:17   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-06-29 16:17 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Hello,

Giuliano Procida <gprocida@google.com> a écrit:

> This patch renames CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY to
> TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY.

This patch lacks a ChangeLog part in the commit log, so I took the
liberty to add it.

> Signed-off-by: Giuliano Procida <gprocida@google.com>

Applied to master, thanks!

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/11] Add incomplete enum support.
  2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
                   ` (10 preceding siblings ...)
  2020-06-10 11:59 ` [PATCH 11/11] Add tests for declaration-only enums Giuliano Procida
@ 2020-07-01 13:36 ` Dodji Seketeli
  2020-07-01 15:18   ` Giuliano Procida
  11 siblings, 1 reply; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-01 13:36 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Hello,

Giuliano Procida <gprocida@google.com> a écrit:

> Hi. This is my latest iteration of incomplete enum support. I think
> more help is needed for abg-reader.cc.
>
> Mirror: https://github.com/myxoid/libabigail/commits/incomplete-enums.

Thank you for working on this.

I am looking at this patchset at the moment.  At this point, patches of
the set that are good to be applied are going to be applied
independantly.  When they lack a ChangeLog part in the commit log, I am
adding that.  If I see changes that are trivial, I'll make them and
apply the patch.  If there are more discussions to be held on a patch,
well, we'll do that.

I hope that is okay.

Thanks!

[...]

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 00/11] Add incomplete enum support.
  2020-07-01 13:36 ` [PATCH 00/11] Add incomplete enum support Dodji Seketeli
@ 2020-07-01 15:18   ` Giuliano Procida
  0 siblings, 0 replies; 32+ messages in thread
From: Giuliano Procida @ 2020-07-01 15:18 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail, kernel-team

Hi Dodji.

On Wed, 1 Jul 2020 at 14:36, Dodji Seketeli <dodji@seketeli.org> wrote:
>
> Hello,
>
> Giuliano Procida <gprocida@google.com> a écrit:
>
> > Hi. This is my latest iteration of incomplete enum support. I think
> > more help is needed for abg-reader.cc.
> >
> > Mirror: https://github.com/myxoid/libabigail/commits/incomplete-enums.
>
> Thank you for working on this.
>
> I am looking at this patchset at the moment.  At this point, patches of
> the set that are good to be applied are going to be applied
> independantly.  When they lack a ChangeLog part in the commit log, I am
> adding that.  If I see changes that are trivial, I'll make them and
> apply the patch.  If there are more discussions to be held on a patch,
> well, we'll do that.
>
> I hope that is okay.

That's fine with me. I don't think I've made any other changes since I
posted this.

I've just been rebasing (and updating the mirror) as other changes come in.

Regards,
Giuliano.

> Thanks!
>
> [...]
>
> Cheers,
>
> --
>                 Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-06-10 11:59 ` [PATCH 10/11] Add declaration-only enums to XML reader/writer Giuliano Procida
@ 2020-07-02 13:55   ` Dodji Seketeli
  2020-07-02 15:09     ` Giuliano Procida
  2020-07-06 11:31   ` Dodji Seketeli
  1 sibling, 1 reply; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-02 13:55 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> Serialisation seems OK.
>
> Deserialisation quite likely needs declaration/definition resolution
> as there is logic for this for class types.

Just for the record, I think that the deserialization doesn't need the
declaration/definition resolution logic, because the resolution happened
already when we analysed the DWARF.  The subsequent serialized abixml
doesn't have improperly resolved declarations anymore.

So I am adding ChangeLog to this patch then, and I think it should be
good to go.  I'll reply later to this patch with the new one when I am
done.

Thanks.

[...]

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-07-02 13:55   ` Dodji Seketeli
@ 2020-07-02 15:09     ` Giuliano Procida
  2020-07-06 11:05       ` Dodji Seketeli
  0 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-07-02 15:09 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail, kernel-team

Hi Dodji.

On Thu, 2 Jul 2020 at 14:55, Dodji Seketeli <dodji@seketeli.org> wrote:
>
> Giuliano Procida <gprocida@google.com> a écrit:
>
> > Serialisation seems OK.
> >
> > Deserialisation quite likely needs declaration/definition resolution
> > as there is logic for this for class types.
>
> Just for the record, I think that the deserialization doesn't need the
> declaration/definition resolution logic, because the resolution happened
> already when we analysed the DWARF.  The subsequent serialized abixml
> doesn't have improperly resolved declarations anymore.

That's good news. I wasn't sure what to make of the existing
resolution logic in the reader code. Does it relate to an older format
of the XML?

Regards,
Giuliano.

> So I am adding ChangeLog to this patch then, and I think it should be
> good to go.  I'll reply later to this patch with the new one when I am
> done.
>
> Thanks.
>
> [...]
>
> Cheers,
>
> --
>                 Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-07-02 15:09     ` Giuliano Procida
@ 2020-07-06 11:05       ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:05 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

[...]

> That's good news. I wasn't sure what to make of the existing
> resolution logic in the reader code. Does it relate to an older format
> of the XML?

Yes it does.  At the time, there was no resolution done in the dwarf
reader.  So it was leaking through the abixml.

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 06/11] Support incomplete enums in core and diff code.
  2020-06-10 11:59 ` [PATCH 06/11] Support incomplete enums in core and diff code Giuliano Procida
@ 2020-07-06 11:14   ` Dodji Seketeli
       [not found]     ` <CAGvU0HkuOc74mfL9yLttK4Riwkrj9tmtc3VXxdHAsaCbn2153A@mail.gmail.com>
  0 siblings, 1 reply; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:14 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Hello,

Giuliano Procida <gprocida@google.com> a écrit:

> This is an almost blind attempt at addition of support for incomplete,
> also known as forward-declared, enum types. I've not made any attempt
> to refactor or share logic with the struct/union code and I've
> probably got other things wrong.
>
> This patch:
>
> - adds enums_type and enum_type_decl_wptr typedefs
> - adds declaration-only machinery to enum_type_decl
> - adds is_compatible_with_enum_type, look_through_decl_only_class,
>   there_is_a_decl_only_enum and lookup_enum_type helpers
> - adds has_enum_decl_only_def_change functions
> - inserts has_enum_decl_only_def_change wherever
>   has_class_decl_only_def_change is present
> - adds reporting of enum declaration/definition diffs
> - doesn't address the DWARF reader, XML writer or XML reader

So, I have amended this patch to make it so that declaration-only-ness
becomes a property of any declaration.  Namely, it becomes a property of
abigail::ir::decl_base.

Besides the obvious code sharing advantage, it allows the underlying
type of enums to also be flagged as decl-only whenever an enum is
decl-only.  Thus, when the underlying type of an enum changes from
decl-only to defined that change is filtered out from the leaf reporter,
as it is for class, unions and now enums.

I have also added a ChangeLog to the commit log of the patch.

You'll find the amended patch below, but you can also get it from the
branch dodji/incomp-enums, browsable online at
https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/dodji/incomp-enums.

From 7dd6e05d28d2f023e6b2158cd517c0b6db8eec5d Mon Sep 17 00:00:00 2001
From: Giuliano Procida <gprocida@google.com>
Date: Wed, 10 Jun 2020 12:59:35 +0100
Subject: [PATCH 1/4] Support incomplete enums in core and diff code.

This is an initial implementation of the support for incomplete, also
known as forward-declared, enum types. I've not made any attempt to
refactor or share logic with the struct/union code.

	* include/abg-comp-filter.h (has_decl_only_def_change) : Declare
	New function.
	* src/abg-comp-filter.cc (there_is_a_decl_only_enum): Define new
	static function and ...
	(type_size_changed): ... use it here.
	(has_decl_only_def_change): Define new function and ...
	(categorize_harm{less, ful}_diff_node): ... use it here.
	* include/abg-fwd.h (enums_type, decl_base_wptr): Declare new
	typedefs.
	(look_through_decl_only_class): Declare new overload for
	class_or_union*.
	(is_compatible_with_enum_type, is_compatible_with_enum_type)
	(look_through_decl_only, lookup_enum_types, lookup_enum_types):
	Declare new functions.
	* include/abg-ir.h (decl_base::{get_is_declaration_only,
	set_is_declaration_only, set_definition_of_declaration,
	get_definition_of_declaration,
	get_naked_definition_of_declaration}): Declare new member
	functions.  They were moved here from the class_or_union class.
	(class_or_union::{get_earlier_declaration,
	set_earlier_declaration, get_definition_of_declaration,
	set_definition_of_declaration,
	get_naked_definition_of_declaration, get_is_declaration_only,
	set_is_declaration_only}): Remove these member functions.
	* src/abg-ir.cc (decl_base::priv::{declaration_,
	definition_of_declaration_, naked_definition_of_declaration_,
	is_declaration_only_}): Define data members.  Moved here from
	class_or_union.
	(decl_base::priv::priv): Adjust to initialize the new data
	members.
	(decl_base::{get_earlier_declaration, set_earlier_declaration,
	get_definition_of_declaration,
	get_naked_definition_of_declaration, get_is_declaration_only,
	set_is_declaration_only, set_definition_of_declaration}): Define
	member functions.
	(operator|): In the overload for (change_kind, change_kind),
	adjust the return type of the call to
	decl_base::get_definition_of_declaration.
	(look_through_decl_only): Define new function.
	(look_through_decl_only_class): Adjust.
	(look_through_decl_only_enum): Likewise.
	(maybe_update_types_lookup_map<class_decl>): Adjust return type of
	call to decl_base::get_definition_of_declaration.
	(types_defined_same_linux_kernel_corpus_public): Use
	look_through_decl_only_class rather than open coding it.
	(class_or_union::priv::{declaration_, definition_of_declaration_,
	naked_definition_of_declaration_, is_declaration_only_}): Remove
	these data members.  They are now carried by decl_base::priv.
	(class_or_union::{g,s}et_alignment_in_bits): Adjust.
	(class_or_union::{g,s}et_size_in_bits): Likewise.
	(class_or_union::operator==): Likewise.
	(equals): Adjust the overload for class_or_union.
	(is_compatible_with_enum_type)
	* src/abg-comparison.cc (try_to_diff<class_decl>): Adjust the
	return type of decl_base::get_definition_of_declaration.
	(leaf_diff_node_marker_visitor::visit_begin): Use
	filtering::has_decl_only_def_change rather than
	filtering::has_class_decl_only_def_change.  Decl-only changes to
	enums (or any other type really) will thus not be recorded as leaf
	changes.
	* src/abg-dwarf-reader.cc (get_scope_for_die): Adjust return type
	of decl_base::get_definition_of_declaration.
	* src/abg-default-reporter.cc (default_reporter::report): Report
	enum decl-only <-> definition changes.
	* src/abg-hash.cc (class_or_union::hash::operator()): In the
	overload for class_or_union& adjust the return type for
	decl_base::get_definition_of_declaration.

Signed-off-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-comp-filter.h   |  14 ++
 include/abg-fwd.h           |  36 ++++
 include/abg-ir.h            |  48 ++---
 src/abg-comp-filter.cc      | 131 ++++++++++++-
 src/abg-comparison.cc       |  10 +-
 src/abg-default-reporter.cc |  19 ++
 src/abg-dwarf-reader.cc     |   3 +-
 src/abg-hash.cc             |   3 +-
 src/abg-ir.cc               | 456 +++++++++++++++++++++++++++-----------------
 9 files changed, 509 insertions(+), 211 deletions(-)

diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h
index 8113003..556bad4 100644
--- a/include/abg-comp-filter.h
+++ b/include/abg-comp-filter.h
@@ -65,13 +65,27 @@ bool
 is_decl_only_class_with_size_change(const diff *diff);
 
 bool
+has_decl_only_def_change(const decl_base_sptr& first,
+			 const decl_base_sptr& second);
+
+bool
+has_decl_only_def_change(const diff *d);
+
+bool
 has_class_decl_only_def_change(const class_or_union_sptr& first,
 			       const class_or_union_sptr& second);
 
 bool
+has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
+			      const enum_type_decl_sptr& second);
+
+bool
 has_class_decl_only_def_change(const diff *diff);
 
 bool
+has_enum_decl_only_def_change(const diff *diff);
+
+bool
 has_basic_type_name_change(const diff *);
 
 bool
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 999b071..7a85db3 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -155,6 +155,12 @@ class enum_type_decl;
 /// Convenience typedef for shared pointer to a @ref enum_type_decl.
 typedef shared_ptr<enum_type_decl> enum_type_decl_sptr;
 
+/// Convenience typedef for a vector of @ref enum_type_decl_sptr
+typedef vector<enum_type_decl_sptr> enums_type;
+
+/// Convenience typedef for a weak pointer to a @ref decl_base.
+typedef weak_ptr<decl_base> decl_base_wptr;
+
 class class_or_union;
 
 typedef shared_ptr<class_or_union> class_or_union_sptr;
@@ -424,6 +430,12 @@ typedef_decl*
 is_typedef(type_base*);
 
 enum_type_decl_sptr
+is_compatible_with_enum_type(const type_base_sptr&);
+
+enum_type_decl_sptr
+is_compatible_with_enum_type(const decl_base_sptr&);
+
+enum_type_decl_sptr
 is_enum_type(const type_or_decl_base_sptr&);
 
 const enum_type_decl*
@@ -513,6 +525,24 @@ look_through_decl_only_class(const class_or_union&);
 class_or_union_sptr
 look_through_decl_only_class(class_or_union_sptr);
 
+class_or_union*
+look_through_decl_only_class(class_or_union*);
+
+enum_type_decl_sptr
+look_through_decl_only_enum(const enum_type_decl&);
+
+enum_type_decl_sptr
+look_through_decl_only_enum(enum_type_decl_sptr);
+
+decl_base_sptr
+look_through_decl_only(const decl_base&);
+
+decl_base*
+look_through_decl_only(decl_base*);
+
+decl_base_sptr
+look_through_decl_only(const decl_base_sptr&);
+
 var_decl*
 is_var_decl(const type_or_decl_base*);
 
@@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&);
 enum_type_decl_sptr
 lookup_enum_type(const interned_string&, const corpus&);
 
+const type_base_wptrs_type*
+lookup_enum_types(const interned_string&, const corpus&);
+
+const type_base_wptrs_type*
+lookup_enum_types(const string&, const corpus&);
+
 enum_type_decl_sptr
 lookup_enum_type_per_location(const interned_string&, const corpus&);
 
diff --git a/include/abg-ir.h b/include/abg-ir.h
index d81de21..468198c 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -1553,6 +1553,27 @@ public:
   void
   set_visibility(visibility v);
 
+  const decl_base_sptr
+  get_earlier_declaration() const;
+
+  void
+  set_earlier_declaration(const decl_base_sptr&);
+
+  const decl_base_sptr
+  get_definition_of_declaration() const;
+
+  void
+  set_definition_of_declaration(const decl_base_sptr&);
+
+  const decl_base*
+  get_naked_definition_of_declaration() const;
+
+  bool
+  get_is_declaration_only() const;
+
+  void
+  set_is_declaration_only(bool f);
+
   friend type_base_sptr
   canonicalize(type_base_sptr);
 
@@ -3781,27 +3802,6 @@ public:
   void
   set_naming_typedef(const typedef_decl_sptr&);
 
-  bool
-  get_is_declaration_only() const;
-
-  void
-  set_is_declaration_only(bool f);
-
-  void
-  set_definition_of_declaration(class_or_union_sptr);
-
-  const class_or_union_sptr
-  get_definition_of_declaration() const;
-
-  const class_or_union*
-  get_naked_definition_of_declaration() const;
-
-  decl_base_sptr
-  get_earlier_declaration() const;
-
-  void
-  set_earlier_declaration(decl_base_sptr declaration);
-
  void
   insert_member_type(type_base_sptr t,
 		     declarations::iterator before);
@@ -4013,12 +4013,6 @@ public:
   class_decl(const environment* env, const string& name, bool is_struct,
 	     bool is_declaration_only = true);
 
-  const class_decl_sptr
-  get_definition_of_declaration() const;
-
-  const class_decl*
-  get_naked_definition_of_declaration() const;
-
   virtual string
   get_pretty_representation(bool internal = false,
 			    bool qualified_name = true) const;
diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
index 702d223..9b87ee7 100644
--- a/src/abg-comp-filter.cc
+++ b/src/abg-comp-filter.cc
@@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1,
   return false;
 }
 
+/// Test if there is a enum that is declaration-only among the two
+/// enums in parameter.
+///
+/// @param enum1 the first enum to consider.
+///
+/// @param enum2 the second enum to consider.
+///
+/// @return true if either enums are declaration-only, false
+/// otherwise.
+static bool
+there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1,
+			  const enum_type_decl_sptr& enum2)
+{
+  if ((enum1 && enum1->get_is_declaration_only())
+      || (enum2 && enum2->get_is_declaration_only()))
+    return true;
+  return false;
+}
+
 /// Test if the diff involves a declaration-only class.
 ///
 /// @param diff the class diff to consider.
@@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s)
       || f->get_size_in_bits() == 0
       || s->get_size_in_bits() == 0
       || there_is_a_decl_only_class(is_compatible_with_class_type(f),
-				    is_compatible_with_class_type(s)))
+				    is_compatible_with_class_type(s))
+      || there_is_a_decl_only_enum(is_compatible_with_enum_type(f),
+				   is_compatible_with_enum_type(s)))
     return false;
 
   return f->get_size_in_bits() != s->get_size_in_bits();
@@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_union_sptr& first,
   if (!first || !second)
     return false;
 
-  class_or_union_sptr f =
-    look_through_decl_only_class(first);
-  class_or_union_sptr s =
-    look_through_decl_only_class(second);
+  class_or_union_sptr f = look_through_decl_only_class(first);
+  class_or_union_sptr s = look_through_decl_only_class(second);
 
   return is_decl_only_class_with_size_change(*f, *s);
 }
@@ -929,6 +948,57 @@ is_decl_only_class_with_size_change(const diff *diff)
   return is_decl_only_class_with_size_change(f, s);
 }
 
+/// Test if two @ref decl_base_sptr are different just by the
+/// fact that one is decl-only and the other one is defined.
+///
+/// @param first the first decl to consider.
+///
+/// @param second the second decl to consider.
+///
+/// @return true iff the two arguments are different just by the fact
+/// that one is decl-only and the other one is defined.
+bool
+has_decl_only_def_change(const decl_base_sptr& first,
+			 const decl_base_sptr& second)
+{
+  if (!first || !second)
+    return false;
+
+  decl_base_sptr f =
+    look_through_decl_only(first);
+  decl_base_sptr s =
+    look_through_decl_only(second);
+
+  if (f->get_qualified_name() != s->get_qualified_name())
+    return false;
+
+  return (f->get_is_declaration_only() != s->get_is_declaration_only());
+}
+
+/// Test if a diff carries a change in which the two decls are
+/// different by the fact that one is a decl-only and the other one is
+/// defined.
+///
+/// @param diff the diff node to consider.
+///
+/// @return true if the diff carries a change in which the two decls
+/// are different by the fact that one is a decl-only and the other
+/// one is defined.
+bool
+has_decl_only_def_change(const diff *d)
+{
+  if (!d)
+    return false;
+
+  decl_base_sptr f =
+    look_through_decl_only(is_decl(d->first_subject()));
+  decl_base_sptr s =
+    look_through_decl_only(is_decl(d->second_subject()));
+
+  return has_decl_only_def_change(f, s);
+}
+
+
 /// Test if two @ref class_or_union_sptr are different just by the
 /// fact that one is decl-only and the other one is defined.
 ///
@@ -956,6 +1026,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
   return (f->get_is_declaration_only() != s->get_is_declaration_only());
 }
 
+/// Test if two @ref enum_sptr are different just by the
+/// fact that one is decl-only and the other one is defined.
+///
+/// @param first the first enum to consider.
+///
+/// @param second the second enum to consider.
+///
+/// @return true iff the two arguments are different just by the fact
+/// that one is decl-only and the other one is defined.
+bool
+has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
+			      const enum_type_decl_sptr& second)
+{
+  if (!first || !second)
+    return false;
+
+  enum_type_decl_sptr f = look_through_decl_only_enum(first);
+  enum_type_decl_sptr s = look_through_decl_only_enum(second);
+
+  if (f->get_qualified_name() != s->get_qualified_name())
+    return false;
+
+  return (f->get_is_declaration_only() != s->get_is_declaration_only());
+}
+
 /// Test if a class_or_union_diff carries a change in which the two
 /// classes are different by the fact that one is a decl-only and the
 /// other one is defined.
@@ -980,6 +1075,28 @@ has_class_decl_only_def_change(const diff *diff)
   return has_class_decl_only_def_change(f, s);
 }
 
+/// Test if a enum_diff carries a change in which the two enums are
+/// different by the fact that one is a decl-only and the other one is
+/// defined.
+///
+/// @param diff the diff node to consider.
+///
+/// @return true if the enum_diff carries a change in which the two
+/// enums are different by the fact that one is a decl-only and the
+/// other one is defined.
+bool
+has_enum_decl_only_def_change(const diff *diff)
+{
+  const enum_diff *d = dynamic_cast<const enum_diff*>(diff);
+  if (!d)
+    return false;
+
+  enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum());
+  enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum());
+
+  return has_enum_decl_only_def_change(f, s);
+}
+
 /// Test if a diff node carries a basic type name change.
 ///
 /// @param d the diff node to consider.
@@ -1517,7 +1634,8 @@ categorize_harmless_diff_node(diff *d, bool pre)
       decl_base_sptr f = is_decl(d->first_subject()),
 	s = is_decl(d->second_subject());
 
-      if (has_class_decl_only_def_change(d))
+      if (has_class_decl_only_def_change(d)
+	  || has_enum_decl_only_def_change(d))
 	category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY;
 
       if (access_changed(f, s))
@@ -1608,6 +1726,7 @@ categorize_harmful_diff_node(diff *d, bool pre)
       //
       // TODO: be more specific -- not all size changes are harmful.
       if (!has_class_decl_only_def_change(d)
+	  && !has_enum_decl_only_def_change(d)
 	  && (type_size_changed(f, s)
 	      || data_member_offset_changed(f, s)
 	      || non_static_data_member_type_size_changed(f, s)
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index d0f1d21..b6f065f 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -2827,13 +2827,15 @@ try_to_diff<class_decl>(const type_or_decl_base_sptr first,
 
       if (f->get_is_declaration_only())
 	{
-	  class_decl_sptr f2 = f->get_definition_of_declaration();
+	  class_decl_sptr f2 =
+	    is_class_type (f->get_definition_of_declaration());
 	  if (f2)
 	    f = f2;
 	}
       if (s->get_is_declaration_only())
 	{
-	  class_decl_sptr s2 = s->get_definition_of_declaration();
+	  class_decl_sptr s2 =
+	    is_class_type(s->get_definition_of_declaration());
 	  if (s2)
 	    s = s2;
 	}
@@ -10953,8 +10955,8 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor
 	// typedef change which underlying type is an anonymous
 	// struct/union.
 	&& !is_anonymous_class_or_union_diff(d)
-	// Don't show decl-only-ness changes of classes either.
-	&& !filtering::has_class_decl_only_def_change(d)
+	// Don't show decl-only-ness changes either.
+	&& !filtering::has_decl_only_def_change(d)
 	// Sometime, we can encounter artifacts of bogus DWARF that
 	// yield a diff node for a decl-only class (and empty class
 	// with the is_declaration flag set) that carries a non-zero
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 2acb695..cbf8c2b 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out,
   enum_type_decl_sptr first = d.first_enum(), second = d.second_enum();
 
   const diff_context_sptr& ctxt = d.context();
+
+  // Report enum decl-only <-> definition changes.
+  if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
+    if (filtering::has_enum_decl_only_def_change(first, second))
+      {
+	string was =
+	  first->get_is_declaration_only()
+	  ? " was a declaration-only enum type"
+	  : " was a defined enum type";
+
+	string is_now =
+	  second->get_is_declaration_only()
+	  ? " and is now a declaration-only enum type"
+	  : " and is now a defined enum type";
+
+	out << indent << "enum type " << name << was << is_now << "\n";
+	return;
+      }
+
   report_name_size_and_alignment_changes(first, second, ctxt,
 					 out, indent);
   maybe_report_diff_for_member(first, second, ctxt, out, indent);
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index cf789d0..afe574d 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -12315,7 +12315,8 @@ get_scope_for_die(read_context& ctxt,
   class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d);
   if (cl && cl->get_is_declaration_only())
     {
-      scope_decl_sptr scop (cl->get_definition_of_declaration());
+      scope_decl_sptr scop  =
+	dynamic_pointer_cast<scope_decl>(cl->get_definition_of_declaration());
       if (scop)
 	s = scop;
       else
diff --git a/src/abg-hash.cc b/src/abg-hash.cc
index c1cdc57..5d2861f 100644
--- a/src/abg-hash.cc
+++ b/src/abg-hash.cc
@@ -635,7 +635,8 @@ class_or_union::hash::operator()(const class_or_union& t) const
   if (t.get_is_declaration_only())
     {
       ABG_ASSERT(t.get_definition_of_declaration());
-      size_t v = operator()(*t.get_definition_of_declaration());
+      size_t v = operator()
+	(*is_class_or_union_type(t.get_definition_of_declaration()));
       return v;
     }
 
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 4813035..940f9ec 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -3416,6 +3416,10 @@ struct decl_base::priv
     interned_string	scoped_name_;
   interned_string	linkage_name_;
   visibility		visibility_;
+  decl_base_sptr	declaration_;
+  decl_base_wptr	definition_of_declaration_;
+  decl_base*		naked_definition_of_declaration_;
+  bool			is_declaration_only_;
 
   priv()
     : in_pub_sym_tab_(false),
@@ -3423,7 +3427,9 @@ struct decl_base::priv
       is_artificial_(false),
       has_anonymous_parent_(false),
       context_(),
-      visibility_(VISIBILITY_DEFAULT)
+      visibility_(VISIBILITY_DEFAULT),
+      naked_definition_of_declaration_(),
+      is_declaration_only_()
   {}
 
   priv(interned_string name, const location& locus,
@@ -3434,7 +3440,9 @@ struct decl_base::priv
       name_(name),
       qualified_name_(name),
       linkage_name_(linkage_name),
-      visibility_(vis)
+      visibility_(vis),
+      naked_definition_of_declaration_(),
+      is_declaration_only_()
   {
     is_anonymous_ = name_.empty();
     has_anonymous_parent_ = false;
@@ -3446,7 +3454,9 @@ struct decl_base::priv
       has_anonymous_parent_(false),
       location_(l),
       context_(),
-      visibility_(VISIBILITY_DEFAULT)
+      visibility_(VISIBILITY_DEFAULT),
+      naked_definition_of_declaration_(),
+      is_declaration_only_()
   {}
 
   ~priv()
@@ -3881,6 +3891,80 @@ const interned_string&
 decl_base::get_scoped_name() const
 {return priv_->scoped_name_;}
 
+/// If this @ref decl_base is a definition, get its earlier
+/// declaration.
+///
+/// @return the earlier declaration of the class, if any.
+const decl_base_sptr
+decl_base::get_earlier_declaration() const
+{return priv_->declaration_;}
+
+/// set the earlier declaration of this @ref decl_base definition.
+///
+/// @param d the earlier declaration to set.  Note that it's set only
+/// if it's a pure declaration.
+void
+decl_base::set_earlier_declaration(const decl_base_sptr& d)
+{
+  if (d && d->get_is_declaration_only())
+    priv_->declaration_ = d;
+}
+
+
+/// If this @ref decl_base is declaration-only, get its definition, if
+/// any.
+///
+/// @return the definition of this decl-only @ref decl_base.
+const decl_base_sptr
+decl_base::get_definition_of_declaration() const
+{return priv_->definition_of_declaration_.lock();}
+
+///  If this @ref decl_base is declaration-only, get its definition,
+///  if any.
+///
+/// Note that this function doesn't return a smart pointer, but rather
+/// the underlying pointer managed by the smart pointer.  So it's as
+/// fast as possible.  This getter is to be used in code paths that
+/// are proven to be performance hot spots; especially, when comparing
+/// sensitive types like enums, classes or unions.  Those are compared
+/// extremely frequently and thus, their access to the definition of
+/// declaration must be fast.
+///
+/// @return the definition of the declaration.
+const decl_base*
+decl_base::get_naked_definition_of_declaration() const
+{return priv_->naked_definition_of_declaration_;}
+
+/// Test if a @ref decl_base is a declaration-only decl.
+///
+/// @return true iff the current @ref decl_base is declaration-only.
+bool
+decl_base::get_is_declaration_only() const
+{return priv_->is_declaration_only_;}
+
+/// Set a flag saying if the @ref enum_type_decl is a declaration-only
+/// @ref enum_type_decl.
+///
+/// @param f true if the @ref enum_type_decl is a decalaration-only
+/// @ref enum_type_decl.
+void
+decl_base::set_is_declaration_only(bool f)
+{
+  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
+
+  priv_->is_declaration_only_ = f;
+
+  if (update_types_lookup_map)
+    if (scope_decl* s = get_scope())
+      {
+	scope_decl::declarations::iterator i;
+	if (s->find_iterator_for_member(this, i))
+	  maybe_update_types_lookup_map(*i);
+	else
+	  ABG_ASSERT_NOT_REACHED;
+      }
+}
+
 change_kind
 operator|(change_kind l, change_kind r)
 {
@@ -6686,7 +6770,7 @@ get_location(const decl_base_sptr& decl)
       if (class_or_union_sptr c = is_class_or_union_type(decl))
 	if (c->get_is_declaration_only() && c->get_definition_of_declaration())
 	  {
-	    c = c->get_definition_of_declaration();
+	    c = is_class_or_union_type(c->get_definition_of_declaration());
 	    loc = c->get_location();
 	  }
     }
@@ -7925,6 +8009,38 @@ typedef_decl*
 is_typedef(type_base* t)
 {return dynamic_cast<typedef_decl*>(t);}
 
+/// Test if a type is a enum. This function looks through typedefs.
+///
+/// @parm t the type to consider.
+///
+/// @return the enum_decl if @p t is a enum_decl or null otherwise.
+enum_type_decl_sptr
+is_compatible_with_enum_type(const type_base_sptr& t)
+{
+  if (!t)
+    return enum_type_decl_sptr();
+
+  // Normally we should strip typedefs entirely, but this is
+  // potentially costly, especially on binaries with huge changesets
+  // like the Linux Kernel.  So we just get the leaf types for now.
+  //
+  // Maybe there should be an option by which users accepts to pay the
+  // CPU usage toll in exchange for finer filtering?
+
+  // type_base_sptr ty = strip_typedef(t);
+  type_base_sptr ty = peel_typedef_type(t);;
+  return is_enum_type(ty);
+}
+
+/// Test if a type is a enum. This function looks through typedefs.
+///
+/// @parm t the type to consider.
+///
+/// @return the enum_decl if @p t is a enum_decl or null otherwise.
+enum_type_decl_sptr
+is_compatible_with_enum_type(const decl_base_sptr& t)
+{return is_compatible_with_enum_type(is_type(t));}
+
 /// Test if a decl is an enum_type_decl
 ///
 /// @param d the decl to test for.
@@ -8270,24 +8386,19 @@ is_method_type(type_or_decl_base* t)
 /// @param the_klass the class (or union) to consider.
 ///
 /// @return either the definition of the class, or the class itself.
+class_or_union*
+look_through_decl_only_class(class_or_union* the_class)
+{return is_class_or_union_type(look_through_decl_only(the_class));}
+
+/// If a class (or union) is a decl-only class, get its definition.
+/// Otherwise, just return the initial class.
+///
+/// @param the_klass the class (or union) to consider.
+///
+/// @return either the definition of the class, or the class itself.
 class_or_union_sptr
 look_through_decl_only_class(const class_or_union& the_class)
-{
-  class_or_union_sptr klass;
-  if (the_class.get_is_declaration_only())
-    klass = the_class.get_definition_of_declaration();
-
-  if (!klass)
-    return klass;
-
-  while (klass
-	 && klass->get_is_declaration_only()
-	 && klass->get_definition_of_declaration())
-    klass = klass->get_definition_of_declaration();
-
-  ABG_ASSERT(klass);
-  return klass;
-}
+{return is_class_or_union_type(look_through_decl_only(the_class));}
 
 /// If a class (or union) is a decl-only class, get its definition.
 /// Otherwise, just return the initial class.
@@ -8297,13 +8408,85 @@ look_through_decl_only_class(const class_or_union& the_class)
 /// @return either the definition of the class, or the class itself.
 class_or_union_sptr
 look_through_decl_only_class(class_or_union_sptr klass)
+{return is_class_or_union_type(look_through_decl_only(klass));}
+
+/// If a enum is a decl-only enum, get its definition.
+/// Otherwise, just return the initial enum.
+///
+/// @param the_enum the enum to consider.
+///
+/// @return either the definition of the enum, or the enum itself.
+enum_type_decl_sptr
+look_through_decl_only_enum(const enum_type_decl& the_enum)
+{return is_enum_type(look_through_decl_only(the_enum));}
+
+/// If a enum is a decl-only enum, get its definition.
+/// Otherwise, just return the initial enum.
+///
+/// @param enom the enum to consider.
+///
+/// @return either the definition of the enum, or the enum itself.
+enum_type_decl_sptr
+look_through_decl_only_enum(enum_type_decl_sptr enom)
+{return is_enum_type(look_through_decl_only(enom));}
+
+/// If a decl is decl-only get its definition.  Otherwise, just return nil.
+///
+/// @param d the decl to consider.
+///
+/// @return either the definition of the decl, or nil.
+decl_base_sptr
+look_through_decl_only(const decl_base& d)
+{
+  decl_base_sptr decl;
+  if (d.get_is_declaration_only())
+    decl = d.get_definition_of_declaration();
+
+  if (!decl)
+    return decl;
+
+  while (decl
+	 && decl->get_is_declaration_only()
+	 && decl->get_definition_of_declaration())
+    decl = decl->get_definition_of_declaration();
+
+  ABG_ASSERT(decl);
+  return decl;
+}
+
+/// If a decl is decl-only enum, get its definition.  Otherwise, just
+/// return the initial decl.
+///
+/// @param d the decl to consider.
+///
+/// @return either the definition of the enum, or the decl itself.
+decl_base*
+look_through_decl_only(decl_base* d)
+{
+  if (!d)
+    return d;
+
+  decl_base* result = look_through_decl_only(*d).get();
+  if (!result)
+    result = d;
+
+  return result;
+}
+
+/// If a decl is decl-only get its definition.  Otherwise, just return nil.
+///
+/// @param d the decl to consider.
+///
+/// @return either the definition of the decl, or nil.
+decl_base_sptr
+look_through_decl_only(const decl_base_sptr& d)
 {
-  if (!klass)
-    return klass;
+  if (!d)
+    return d;
 
-  class_or_union_sptr result = look_through_decl_only_class(*klass);
+  decl_base_sptr result = look_through_decl_only(*d);
   if (!result)
-    result = klass;
+    result = d;
 
   return result;
 }
@@ -10166,6 +10349,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp)
   return result;
 }
 
+/// Look into a given corpus to find the enum type*s* that have a
+/// given qualified name.
+///
+/// @param qualified_name the qualified name of the type to look for.
+///
+/// @param corp the corpus to look into.
+///
+/// @return the vector of enum types that which name is @p qualified_name.
+const type_base_wptrs_type *
+lookup_enum_types(const interned_string& qualified_name, const corpus& corp)
+{
+  const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types();
+
+  return lookup_types_in_map(qualified_name, m);
+}
+
+/// Look into a given corpus to find the enum type*s* that have a
+/// given qualified name.
+///
+/// @param qualified_name the qualified name of the type to look for.
+///
+/// @param corp the corpus to look into.
+///
+/// @return the vector of enum types that which name is @p qualified_name.
+const type_base_wptrs_type*
+lookup_enum_types(const string& qualified_name, const corpus& corp)
+{
+  interned_string s = corp.get_environment()->intern(qualified_name);
+  return lookup_enum_types(s, corp);
+}
+
 /// Look up an @ref enum_type_decl from a given corpus, by its location.
 ///
 /// @param loc the location to consider.
@@ -10767,7 +10981,8 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type,
   bool update_qname_map = true;
   if (type->get_is_declaration_only())
     {
-      if (class_decl_sptr def = class_type->get_definition_of_declaration())
+      if (class_decl_sptr def =
+	  is_class_type(class_type->get_definition_of_declaration()))
 	type = def;
       else
 	update_qname_map = false;
@@ -11683,10 +11898,8 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
 
   // Look through declaration-only types.  That is, get the associated
   // definition type.
-  if (c1 && c1->get_is_declaration_only())
-    c1 = c1->get_definition_of_declaration().get();
-  if (c2 && c2->get_is_declaration_only())
-    c2 = c2->get_definition_of_declaration().get();
+  c1 = look_through_decl_only_class(c1);
+  c2 = look_through_decl_only_class(c2);
 
   if (c1 && c2)
     {
@@ -12084,6 +12297,22 @@ re_canonicalize(type_base_sptr t)
   return canonicalize(t);
 }
 
+/// Set the definition of this declaration-only @ref decl_base.
+///
+/// @param d the new definition to set.
+void
+decl_base::set_definition_of_declaration(const decl_base_sptr& d)
+{
+  ABG_ASSERT(get_is_declaration_only());
+  priv_->definition_of_declaration_ = d;
+  priv_->definition_of_declaration_ = d;
+  if (type_base *t = is_type(this))
+    if (type_base_sptr canonical_type = is_type(d)->get_canonical_type())
+      t->priv_->canonical_type = canonical_type;
+
+  priv_->naked_definition_of_declaration_ = const_cast<decl_base*>(d.get());
+}
+
 /// The constructor of @ref type_base.
 ///
 /// @param s the size of the type, in bits.
@@ -14983,7 +15212,6 @@ class enum_type_decl::priv
   priv();
 
 public:
-
   priv(type_base_sptr underlying_type,
        enumerators& enumerators)
     : underlying_type_(underlying_type),
@@ -17992,9 +18220,6 @@ function_decl::parameter::get_pretty_representation(bool internal,
 struct class_or_union::priv
 {
   typedef_decl_wptr		naming_typedef_;
-  decl_base_sptr		declaration_;
-  class_or_union_wptr		definition_of_declaration_;
-  class_or_union*		naked_definition_of_declaration_;
   member_types			member_types_;
   data_members			data_members_;
   data_members			non_static_data_members_;
@@ -18006,21 +18231,16 @@ struct class_or_union::priv
   string_mem_fn_ptr_map_type	signature_2_mem_fn_map_;
   member_function_templates	member_function_templates_;
   member_class_templates	member_class_templates_;
-  bool				is_declaration_only_;
 
   priv()
-    : naked_definition_of_declaration_(),
-      is_declaration_only_(false)
   {}
 
   priv(class_or_union::member_types& mbr_types,
        class_or_union::data_members& data_mbrs,
        class_or_union::member_functions& mbr_fns)
-    : naked_definition_of_declaration_(),
-      member_types_(mbr_types),
+    : member_types_(mbr_types),
       data_members_(data_mbrs),
-      member_functions_(mbr_fns),
-      is_declaration_only_(false)
+      member_functions_(mbr_fns)
   {
     for (data_members::const_iterator i = data_members_.begin();
 	 i != data_members_.end();
@@ -18029,11 +18249,6 @@ struct class_or_union::priv
 	non_static_data_members_.push_back(*i);
   }
 
-  priv(bool is_declaration_only)
-    : naked_definition_of_declaration_(),
-      is_declaration_only_(is_declaration_only)
-  {}
-
   /// Mark a class or union or union as being currently compared using
   /// the class_or_union== operator.
   ///
@@ -18249,8 +18464,10 @@ class_or_union::class_or_union(const environment* env, const string& name,
     decl_base(env, name, location(), name),
     type_base(env, 0, 0),
     scope_type_decl(env, name, 0, 0, location()),
-    priv_(new priv(is_declaration_only))
-{}
+    priv_(new priv)
+{
+  set_is_declaration_only(is_declaration_only);
+}
 
 /// This implements the ir_traversable_base::traverse pure virtual
 /// function.
@@ -18470,7 +18687,8 @@ size_t
 class_or_union::get_alignment_in_bits() const
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    return get_definition_of_declaration()->get_alignment_in_bits();
+    return is_class_or_union_type
+      (get_definition_of_declaration())->get_alignment_in_bits();
 
    return type_base::get_alignment_in_bits();
 }
@@ -18485,7 +18703,8 @@ void
 class_or_union::set_alignment_in_bits(size_t a)
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    get_definition_of_declaration()->set_alignment_in_bits(a);
+    is_class_or_union_type
+      (get_definition_of_declaration()) ->set_alignment_in_bits(a);
   else
     type_base::set_alignment_in_bits(a);
 }
@@ -18500,7 +18719,8 @@ void
 class_or_union::set_size_in_bits(size_t s)
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    get_definition_of_declaration()->set_size_in_bits(s);
+    is_class_or_union_type
+      (get_definition_of_declaration())->set_size_in_bits(s);
   else
     type_base::set_size_in_bits(s);
 }
@@ -18515,42 +18735,12 @@ size_t
 class_or_union::get_size_in_bits() const
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    return get_definition_of_declaration()->get_size_in_bits();
+    return is_class_or_union_type
+      (get_definition_of_declaration())->get_size_in_bits();
 
   return type_base::get_size_in_bits();
 }
 
-/// Test if a @ref class_or_union is a declaration-only @ref
-/// class_or_union.
-///
-/// @return true iff the current @ref class_or_union is a
-/// declaration-only @ref class_or_union.
-bool
-class_or_union::get_is_declaration_only() const
-{return priv_->is_declaration_only_;}
-
-/// Set a flag saying if the @ref class_or_union is a declaration-only
-/// @ref class_or_union.
-///
-/// @param f true if the @ref class_or_union is a decalaration-only
-/// @ref class_or_union.
-void
-class_or_union::set_is_declaration_only(bool f)
-{
-  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
-
-  priv_->is_declaration_only_ = f;
-
-  if (update_types_lookup_map)
-    if (scope_decl* s = get_scope())
-      {
-	declarations::iterator i;
-	if (s->find_iterator_for_member(this, i))
-	  maybe_update_types_lookup_map(*i);
-	else
-	  ABG_ASSERT_NOT_REACHED;
-      }
-}
 
 /// Getter for the naming typedef of the current class.
 ///
@@ -18582,64 +18772,6 @@ class_or_union::set_naming_typedef(const typedef_decl_sptr& typedef_type)
   priv_->naming_typedef_ = typedef_type;
 }
 
-/// Set the definition of this declaration-only @ref class_or_union.
-///
-/// @param d the new definition to set.
-void
-class_or_union::set_definition_of_declaration(class_or_union_sptr d)
-{
-  ABG_ASSERT(get_is_declaration_only());
-  priv_->definition_of_declaration_ = d;
-  if (d->get_canonical_type())
-    type_base::priv_->canonical_type = d->get_canonical_type();
-
-  priv_->naked_definition_of_declaration_ = d.get();
-}
-
-/// If this @ref class_or_union_sptr is declaration-only, get its
-/// definition, if any.
-///
-/// @return the definition of this decl-only class.
-const class_or_union_sptr
-class_or_union::get_definition_of_declaration() const
-{return priv_->definition_of_declaration_.lock();}
-
-///  If this @ref class_or_union is declaration-only, get its
-///  definition, if any.
-///
-/// Note that this function doesn't return a smart pointer, but rather
-/// the underlying pointer managed by the smart pointer.  So it's as
-/// fast as possible.  This getter is to be used in code paths that
-/// are proven to be performance hot spots; especially, when comparing
-/// sensitive types like class or unions.  Those are compared
-/// extremely frequently and thus, their access to the definition of
-/// declaration must be fast.
-///
-/// @return the definition of the class.
-const class_or_union*
-class_or_union::get_naked_definition_of_declaration() const
-{return priv_->naked_definition_of_declaration_;}
-
-/// If this @ref class_or_union_sptr is a definitin, get its earlier
-/// declaration.
-///
-/// @return the earlier declaration of the class, if any.
-decl_base_sptr
-class_or_union::get_earlier_declaration() const
-{return priv_->declaration_;}
-
-/// set the earlier declaration of this @ref class_or_union definition.
-///
-/// @param declaration the earlier declaration to set.  Note that it's
-/// set only if it's a pure declaration.
-void
-class_or_union::set_earlier_declaration(decl_base_sptr declaration)
-{
-  class_or_union_sptr cl = dynamic_pointer_cast<class_or_union>(declaration);
-  if (cl && cl->get_is_declaration_only())
-    priv_->declaration_ = declaration;
-}
-
 /// Get the member types of this @ref class_or_union.
 ///
 /// @return a vector of the member types of this ref class_or_union.
@@ -19087,15 +19219,16 @@ class_or_union::operator==(const decl_base& other) const
   if (!canonical_type
       && get_is_declaration_only()
       && get_naked_definition_of_declaration())
-    canonical_type =
-      get_naked_definition_of_declaration()->get_naked_canonical_type();
+    canonical_type = is_class_or_union_type
+      (get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   // Likewise for the other class.
   if (!other_canonical_type
       && op->get_is_declaration_only()
       && op->get_naked_definition_of_declaration())
     other_canonical_type =
-      op->get_naked_definition_of_declaration()->get_naked_canonical_type();
+      is_class_or_union_type
+      (op->get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   if (canonical_type && other_canonical_type)
     return canonical_type == other_canonical_type;
@@ -19166,11 +19299,11 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
   if (l_is_decl_only || r_is_decl_only)
     {
       const class_or_union* def1 = l_is_decl_only
-	? l.get_naked_definition_of_declaration()
+	? is_class_or_union_type(l.get_naked_definition_of_declaration())
 	: &l;
 
       const class_or_union* def2 = r_is_decl_only
-	? r.get_naked_definition_of_declaration()
+	? is_class_or_union_type(r.get_naked_definition_of_declaration())
 	: &r;
 
       if (!def1 || !def2)
@@ -19682,30 +19815,6 @@ class_decl::on_canonical_type_set()
     sort_virtual_member_functions(i->second);
 }
 
-///  If this @ref class_decl is declaration-only, get its definition,
-///  if any.
-///
-/// @return the definition of the class.
-const class_decl_sptr
-class_decl::get_definition_of_declaration() const
-{return is_class_type(class_or_union::get_definition_of_declaration());}
-
-///  If this @ref class_decl is declaration-only, get its definition,
-///  if any.
-///
-/// Note that this function doesn't return a smart pointer, but rather
-/// the underlying pointer managed by the smart pointer.  So it's as
-/// fast as possible.  This getter is to be used in code paths that
-/// are proven to be performance hot spots; especially, when comparing
-/// sensitive types like class or unions.  Those are compared
-/// extremely frequently and thus, their access to the definition of
-/// declaration must be fast.
-///
-/// @return the definition of the class.
-const class_decl*
-class_decl::get_naked_definition_of_declaration() const
-{return is_class_type(class_or_union::get_naked_definition_of_declaration());}
-
 /// Set the "is-struct" flag of the class.
 ///
 /// @param f the new value of the flag.
@@ -20836,14 +20945,16 @@ class_decl::operator==(const decl_base& other) const
       && get_is_declaration_only()
       && get_naked_definition_of_declaration())
     canonical_type =
-      get_naked_definition_of_declaration()->get_naked_canonical_type();
+      is_class_type
+      (get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   // Likewise for the other class.
   if (!other_canonical_type
       && op->get_is_declaration_only()
       && op->get_naked_definition_of_declaration())
     other_canonical_type =
-      op->get_naked_definition_of_declaration()->get_naked_canonical_type();
+      is_class_type
+      (op->get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   if (canonical_type && other_canonical_type)
     return canonical_type == other_canonical_type;
@@ -22845,7 +22956,8 @@ hash_type(const type_base *t)
 	// The is a declaration-only class, so it has no canonical
 	// type; but then it's class definition has one.  Let's
 	// use that one.
-	return hash_type(cl->get_naked_definition_of_declaration());
+	return hash_type
+	  (is_class_type(cl->get_naked_definition_of_declaration()));
       else
 	{
 	  // The class really has no canonical type, let's use the
-- 
1.8.3.1


-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 07/11] Add invariant to enum_type_decl::set_is_declaration_only
  2020-06-10 11:59 ` [PATCH 07/11] Add invariant to enum_type_decl::set_is_declaration_only Giuliano Procida
@ 2020-07-06 11:15   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:15 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> From: Dodji Seketeli <dodji@redhat.com>
>
> A declaration-only enum can't have enumerators, so let's enact that
> invariant.
>
> 	* src/abg-ir.cc (enum_type_decl::set_is_declaration_only): assert
> 	that a declaration-only enum can't have enumerator.

This patch becomes useless as the decl-only-ness is now a property of
decl_base.

So, I am dropping it from the set.

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 08/11] Support declaration-only enums in DWARF reader.
  2020-06-10 11:59 ` [PATCH 08/11] Support declaration-only enums in DWARF reader Giuliano Procida
@ 2020-07-06 11:22   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:22 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> This patch adds declaration-only handling enums to the DWARF reader,
> except for support in get_opaque_version_of_type.

I have amended this patch to fuse it with this one: 
    "[PATCH 09/11] Support constructing opaque types for enums"
, add a ChangeLog part to its commit log and make some ancillary changes
like ensuring that the underlying type of the enum is also flagged
decl-only when the enum is decl-only.  This helps to filter out spurious
changes decl-only-ness changes to to underlying types of enums.

I am adding the resulting patch below, but it can also be retrived from
the branch dodji/incomp-enums browsable from
https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/dodji/incomp-enums.

Cheers,

From 2351d1ee8b3597980ecd43e1f677ace4d28eae6c Mon Sep 17 00:00:00 2001
From: Dodji Seketeli <dodji@redhat.com>
Date: Wed, 10 Jun 2020 12:59:38 +0100
Subject: [PATCH 2/4] Support declaration-only enums in DWARF reader.

This patch adds declaration-only handling enums to the DWARF reader.

	* src/abg-dwarf-reader.cc (string_enums_map): Define new
	convenience typedef.
	(read_context::decl_only_enums_map_): Define new data member.
	(read_context::{declaration_only_enums,
	is_decl_only_enum_scheduled_for_resolution,
	resolve_declaration_only_enums}): Define new member functions.
	(build_internal_underlying_enum_type_name)
	(build_enum_underlying_type): Factorize these functions out of ...
	(build_enum_type): ... here.  Detect a decl-only enum and flag it
	as such.  If the enum type is decl-only, then set its underlying
	type as decl-only as well.
	(build_enum_underlying_type): Mark the underlying type as
	artificial.
	(get_opaque_version_of_type): Make this handle enums as well.  So
	make its return type be type_or_decl_base_sptr, rather than just
	class_or_union_sptr as it used to be.
	(read_debug_info_into_corpus): Add logging to trace decl-only
	enums resolution.
	(build_ir_node_from_die): Detect when a suppression specification
	makes an enum opaque.  In that case, get an opaque version of the
	enum type by invoking get_opaque_version_of_type.  Note that
	get_opaque_version_of_type doesn't support returning opaque
	-- i.e, decl-only enum types -- yet, but this is going to be
	handled in a subsequent patch.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-dwarf-reader.cc | 379 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 348 insertions(+), 31 deletions(-)

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index afe574d..dd9921a 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -198,6 +198,10 @@ typedef unordered_map<Dwarf_Off, Dwarf_Off> offset_offset_map_type;
 /// value is a vector of smart pointer to a class.
 typedef unordered_map<string, classes_type> string_classes_map;
 
+/// Convenience typedef for a map which key is a string and which
+/// value is a vector of smart pointer to a enum.
+typedef unordered_map<string, enums_type> string_enums_map;
+
 /// The abstraction of the place where a partial unit has been
 /// imported.  This is what the DW_TAG_imported_unit DIE expresses.
 ///
@@ -434,12 +438,15 @@ static string
 build_internal_anonymous_die_name(const string &base_name,
 				  size_t anonymous_type_index);
 
-
 static string
 get_internal_anonymous_die_name(Dwarf_Die *die,
 				size_t anonymous_type_index);
 
 static string
+build_internal_underlying_enum_type_name(const string &base_name,
+					 bool is_anonymous);
+
+static string
 die_qualified_type_name(const read_context& ctxt,
 			const Dwarf_Die* die,
 			size_t where);
@@ -2233,6 +2240,7 @@ public:
   vector<Dwarf_Off>		type_unit_types_to_canonicalize_;
   vector<type_base_sptr>	extra_types_to_canonicalize_;
   string_classes_map		decl_only_classes_map_;
+  string_enums_map		decl_only_enums_map_;
   die_tu_map_type		die_tu_map_;
   corpus_group_sptr		cur_corpus_group_;
   corpus_sptr			cur_corpus_;
@@ -4442,6 +4450,203 @@ public:
       }
   }
 
+  /// Getter for the map of declaration-only enums that are to be
+  /// resolved to their definition enums by the end of the corpus
+  /// loading.
+  ///
+  /// @return a map of string -> vector of enums where the key is
+  /// the fully qualified name of the enum and the value is the
+  /// vector of declaration-only enum.
+  const string_enums_map&
+  declaration_only_enums() const
+  {return decl_only_enums_map_;}
+
+  /// Getter for the map of declaration-only enums that are to be
+  /// resolved to their definition enums by the end of the corpus
+  /// loading.
+  ///
+  /// @return a map of string -> vector of enums where the key is
+  /// the fully qualified name of the enum and the value is the
+  /// vector of declaration-only enum.
+  string_enums_map&
+  declaration_only_enums()
+  {return decl_only_enums_map_;}
+
+  /// If a given enum is a declaration-only enum then stash it on
+  /// the side so that at the end of the corpus reading we can resolve
+  /// it to its definition.
+  ///
+  /// @param enom the enum to consider.
+  void
+  maybe_schedule_declaration_only_enum_for_resolution(enum_type_decl_sptr& enom)
+  {
+    if (enom->get_is_declaration_only()
+	&& enom->get_definition_of_declaration() == 0)
+      {
+	string qn = enom->get_qualified_name();
+	string_enums_map::iterator record =
+	  declaration_only_enums().find(qn);
+	if (record == declaration_only_enums().end())
+	  declaration_only_enums()[qn].push_back(enom);
+	else
+	  record->second.push_back(enom);
+      }
+  }
+
+  /// Test if a given declaration-only enum has been scheduled for
+  /// resolution to a defined enum.
+  ///
+  /// @param enom the enum to consider for the test.
+  ///
+  /// @return true iff @p enom is a declaration-only enum and if
+  /// it's been scheduled for resolution to a defined enum.
+  bool
+  is_decl_only_enum_scheduled_for_resolution(enum_type_decl_sptr& enom)
+  {
+    if (enom->get_is_declaration_only())
+      return (declaration_only_enums().find(enom->get_qualified_name())
+	      != declaration_only_enums().end());
+
+    return false;
+  }
+
+  /// Walk the declaration-only enums that have been found during
+  /// the building of the corpus and resolve them to their definitions.
+  void
+  resolve_declaration_only_enums()
+  {
+    vector<string> resolved_enums;
+
+    for (string_enums_map::iterator i =
+	   declaration_only_enums().begin();
+	 i != declaration_only_enums().end();
+	 ++i)
+      {
+	bool to_resolve = false;
+	for (enums_type::iterator j = i->second.begin();
+	     j != i->second.end();
+	     ++j)
+	  if ((*j)->get_is_declaration_only()
+	      && ((*j)->get_definition_of_declaration() == 0))
+	    to_resolve = true;
+
+	if (!to_resolve)
+	  {
+	    resolved_enums.push_back(i->first);
+	    continue;
+	  }
+
+	// Now, for each decl-only enum that have the current name
+	// 'i->first', let's try to poke at the fully defined enum
+	// that is defined in the same translation unit as the
+	// declaration.
+	//
+	// If we find one enum (defined in the TU of the declaration)
+	// that defines the declaration, then the declaration can be
+	// resolved to that enum.
+	//
+	// If no defining enum is found in the TU of the declaration,
+	// then there are possibly three cases to consider:
+	//
+	//   1/ There is exactly one enum that defines the
+	//   declaration and that enum is defined in another TU.  In
+	//   this case, the declaration is resolved to that
+	//   definition.
+	//
+	//   2/ There are more than one enum that define that
+	//   declaration and none of them is defined in the TU of the
+	//   declaration.  In this case, the declaration is left
+	//   unresolved.
+	//
+	//   3/ No enum defines the declaration.  In this case, the
+	//   declaration is left unresoved.
+
+	// So get the enums that might define the current
+	// declarations which name is i->first.
+	const type_base_wptrs_type *enums =
+	  lookup_enum_types(i->first, *current_corpus());
+	if (!enums)
+	  continue;
+
+	unordered_map<string, enum_type_decl_sptr> per_tu_enum_map;
+	for (type_base_wptrs_type::const_iterator c = enums->begin();
+	     c != enums->end();
+	     ++c)
+	  {
+	    enum_type_decl_sptr enom = is_enum_type(type_base_sptr(*c));
+	    ABG_ASSERT(enom);
+
+	    enom = is_enum_type(look_through_decl_only_enum(enom));
+	    if (enom->get_is_declaration_only())
+	      continue;
+
+	    string tu_path = enom->get_translation_unit()->get_absolute_path();
+	    if (tu_path.empty())
+	      continue;
+
+	    // Build a map that associates the translation unit path
+	    // to the enum (that potentially defines the declarations
+	    // that we consider) that are defined in that translation unit.
+	    per_tu_enum_map[tu_path] = enom;
+	  }
+
+	if (!per_tu_enum_map.empty())
+	  {
+	    // Walk the declarations to resolve and resolve them
+	    // either to the definitions that are in the same TU as
+	    // the declaration, or to the definition found elsewhere,
+	    // if there is only one such definition.
+	    for (enums_type::iterator j = i->second.begin();
+		 j != i->second.end();
+		 ++j)
+	      {
+		if ((*j)->get_is_declaration_only()
+		    && ((*j)->get_definition_of_declaration() == 0))
+		  {
+		    string tu_path =
+		      (*j)->get_translation_unit()->get_absolute_path();
+		    unordered_map<string, enum_type_decl_sptr>::const_iterator e =
+		      per_tu_enum_map.find(tu_path);
+		    if (e != per_tu_enum_map.end())
+		      (*j)->set_definition_of_declaration(e->second);
+		    else if (per_tu_enum_map.size() == 1)
+		      (*j)->set_definition_of_declaration
+			(per_tu_enum_map.begin()->second);
+		  }
+	      }
+	    resolved_enums.push_back(i->first);
+	  }
+      }
+
+    size_t num_decl_only_enums = declaration_only_enums().size(),
+      num_resolved = resolved_enums.size();
+    if (show_stats())
+      cerr << "resolved " << num_resolved
+	   << " enum declarations out of "
+	   << num_decl_only_enums
+	   << "\n";
+
+    for (vector<string>::const_iterator i = resolved_enums.begin();
+	 i != resolved_enums.end();
+	 ++i)
+      declaration_only_enums().erase(*i);
+
+    for (string_enums_map::iterator i = declaration_only_enums().begin();
+	 i != declaration_only_enums().end();
+	 ++i)
+      {
+	if (show_stats())
+	  {
+	    if (i == declaration_only_enums().begin())
+	      cerr << "Here are the "
+		   << num_decl_only_enums - num_resolved
+		   << " unresolved enum declarations:\n";
+	    else
+	      cerr << "    " << i->first << "\n";
+	  }
+      }
+  }
+
   /// Some functions described by DWARF may have their linkage name
   /// set, but no link to their actual underlying elf symbol.  When
   /// these are virtual member functions, comparing the enclosing type
@@ -10268,6 +10473,29 @@ build_internal_anonymous_die_name(const string &base_name,
   return name;
 }
 
+/// Build the internal name of the underlying type of an enum.
+///
+/// @param base_name the (unqualified) name of the enum the underlying
+/// type is destined to.
+///
+/// @param is_anonymous true if the underlying type of the enum is to
+/// be anonymous.
+static string
+build_internal_underlying_enum_type_name(const string &base_name,
+					 bool is_anonymous = true)
+{
+  std::ostringstream o;
+
+  if (is_anonymous)
+    o << "unnamed-enum";
+  else
+    o << "enum-" << base_name;
+
+  o << "-underlying-type";
+
+  return o.str();
+}
+
 /// Build a full internal anonymous type name.
 ///
 /// @param die the DIE representing the anonymous type to consider.
@@ -12775,6 +13003,40 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
   return result;
 }
 
+/// Construct the type that is to be used as the underlying type of an
+/// enum.
+///
+/// @param ctxt the read context to use.
+///
+/// @param enum_name the name of the enum that this type is going to
+/// be the underlying type of.
+///
+/// @param enum_size the size of the enum.
+///
+/// @param is_anonymous whether the underlying type is anonymous or
+/// not. By default, this should be set to true as before c++11 (and
+/// in C), it's almost the case.
+static type_decl_sptr
+build_enum_underlying_type(read_context& ctxt,
+			   string enum_name,
+			   uint64_t enum_size,
+			   bool is_anonymous = true)
+{
+  string underlying_type_name =
+    build_internal_underlying_enum_type_name(enum_name, is_anonymous);
+
+  type_decl_sptr result(new type_decl(ctxt.env(), underlying_type_name,
+				      enum_size, enum_size, location()));
+  result->set_is_anonymous(is_anonymous);
+  result->set_is_artificial(true);
+  translation_unit_sptr tu = ctxt.cur_transl_unit();
+  decl_base_sptr d = add_decl_to_scope(result, tu->get_global_scope().get());
+  result = dynamic_pointer_cast<type_decl>(d);
+  ABG_ASSERT(result);
+  canonicalize(result);
+  return result;
+}
+
 /// Build an enum_type_decl from a DW_TAG_enumeration_type DIE.
 ///
 /// @param ctxt the read context to use.
@@ -12803,6 +13065,7 @@ build_enum_type(read_context&	ctxt,
   string name, linkage_name;
   location loc;
   die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  bool is_declaration_only = die_is_declaration_only(die);
 
   bool is_anonymous = false;
   // If the enum is anonymous, let's give it a name.
@@ -12860,15 +13123,6 @@ build_enum_type(read_context&	ctxt,
 
   // for now we consider that underlying types of enums are all anonymous
   bool enum_underlying_type_is_anonymous= true;
-  string underlying_type_name;
-  if (enum_underlying_type_is_anonymous)
-    {
-      underlying_type_name = "unnamed-enum";
-      enum_underlying_type_is_anonymous = true;
-    }
-  else
-    underlying_type_name = string("enum-") + name;
-  underlying_type_name += "-underlying-type";
 
   enum_type_decl::enumerators enms;
   Dwarf_Die child;
@@ -12893,20 +13147,19 @@ build_enum_type(read_context&	ctxt,
   // underlying type, so let's create an artificial one here, which
   // sole purpose is to be passed to the constructor of the
   // enum_type_decl type.
-  type_decl_sptr t(new type_decl(ctxt.env(), underlying_type_name,
-				 size, size, location()));
-  t->set_is_anonymous(enum_underlying_type_is_anonymous);
-  translation_unit_sptr tu = ctxt.cur_transl_unit();
-  decl_base_sptr d =
-    add_decl_to_scope(t, tu->get_global_scope().get());
-  canonicalize(t);
+  type_decl_sptr t =
+    build_enum_underlying_type(ctxt, name, size,
+			       enum_underlying_type_is_anonymous);
+  t->set_is_declaration_only(is_declaration_only);
 
-  t = dynamic_pointer_cast<type_decl>(d);
-  ABG_ASSERT(t);
   result.reset(new enum_type_decl(name, loc, t, enms, linkage_name));
   result->set_is_anonymous(is_anonymous);
+  result->set_is_declaration_only(is_declaration_only);
   result->set_is_artificial(is_artificial);
   ctxt.associate_die_to_type(die, result, where_offset);
+
+  ctxt.maybe_schedule_declaration_only_enum_for_resolution(result);
+
   return result;
 }
 
@@ -15147,7 +15400,8 @@ type_is_suppressed(const read_context& ctxt,
 /// a private type.
 ///
 /// The opaque version version of the type is just a declared-only
-/// version of the type (class or union type) denoted by @p type_die.
+/// version of the type (class, union or enum type) denoted by @p
+/// type_die.
 ///
 /// @param ctxt the read context in use.
 ///
@@ -15162,13 +15416,13 @@ type_is_suppressed(const read_context& ctxt,
 ///
 /// @return the opaque version of the type denoted by @p type_die or
 /// nil if no opaque version was found.
-static class_or_union_sptr
+static type_or_decl_base_sptr
 get_opaque_version_of_type(read_context	&ctxt,
 			   scope_decl		*scope,
 			   Dwarf_Die		*type_die,
 			   size_t		where_offset)
 {
-  class_or_union_sptr result;
+  type_or_decl_base_sptr result;
 
   if (type_die == 0)
     return result;
@@ -15176,7 +15430,14 @@ get_opaque_version_of_type(read_context	&ctxt,
   unsigned tag = dwarf_tag(type_die);
   if (tag != DW_TAG_class_type
       && tag != DW_TAG_structure_type
-      && tag != DW_TAG_union_type)
+      && tag != DW_TAG_union_type
+      && tag != DW_TAG_enumeration_type)
+    return result;
+
+  if (tag == DW_TAG_union_type)
+    // TODO: also handle declaration-only unions.  To do that, we mostly
+    // need to adapt add_or_update_union_type to make it schedule
+    // declaration-only unions for resolution too.
     return result;
 
   string type_name, linkage_name;
@@ -15187,17 +15448,19 @@ get_opaque_version_of_type(read_context	&ctxt,
 
   string qualified_name = build_qualified_name(scope, type_name);
 
+  //
   // TODO: also handle declaration-only unions.  To do that, we mostly
   // need to adapt add_or_update_union_type to make it schedule
   // declaration-only unions for resolution too.
-  string_classes_map::const_iterator i =
-    ctxt.declaration_only_classes().find(qualified_name);
-  if (i != ctxt.declaration_only_classes().end())
-    result = i->second.back();
-
-  if (!result)
+  //
+  if (tag == DW_TAG_structure_type || tag == DW_TAG_class_type)
     {
-      if (tag == DW_TAG_class_type || tag == DW_TAG_structure_type)
+      string_classes_map::const_iterator i =
+	ctxt.declaration_only_classes().find(qualified_name);
+      if (i != ctxt.declaration_only_classes().end())
+	result = i->second.back();
+
+      if (!result)
 	{
 	  // So we didn't find any pre-existing forward-declared-only
 	  // class for the class definition that we could return as an
@@ -15217,6 +15480,31 @@ get_opaque_version_of_type(read_context	&ctxt,
 	}
     }
 
+  if (tag == DW_TAG_enumeration_type)
+    {
+      string_enums_map::const_iterator i =
+	ctxt.declaration_only_enums().find(qualified_name);
+      if (i != ctxt.declaration_only_enums().end())
+	result = i->second.back();
+
+      if (!result)
+	{
+	  uint64_t size = 0;
+	  if (die_unsigned_constant_attribute(type_die, DW_AT_byte_size, size))
+	    size *= 8;
+	  type_decl_sptr underlying_type =
+	    build_enum_underlying_type(ctxt, type_name, size,
+				       /*anonymous=*/true);
+	  enum_type_decl::enumerators enumeratorz;
+	  enum_type_decl_sptr enum_type (new enum_type_decl(type_name,
+							    type_location,
+							    underlying_type,
+							    enumeratorz,
+							    linkage_name));
+	  result = enum_type;
+	}
+    }
+
   return result;
 }
 
@@ -15622,6 +15910,24 @@ read_debug_info_into_corpus(read_context& ctxt)
     tools_utils::timer t;
     if (ctxt.do_log())
       {
+	cerr << "resolving declaration only enums ...";
+	t.start();
+      }
+    ctxt.resolve_declaration_only_enums();
+    if (ctxt.do_log())
+      {
+	t.stop();
+	cerr << " DONE@" << ctxt.current_corpus()->get_path()
+	     << ":"
+	     << t
+	     <<"\n";
+      }
+  }
+
+  {
+    tools_utils::timer t;
+    if (ctxt.do_log())
+      {
 	cerr << "fixing up functions with linkage name but "
 	     << "no advertised underlying symbols ....";
 	t.start();
@@ -16050,7 +16356,18 @@ build_ir_node_from_die(read_context&	ctxt,
 
     case DW_TAG_enumeration_type:
       {
-	if (!type_is_suppressed(ctxt, scope, die))
+	bool type_is_private = false;
+	bool type_suppressed =
+	  type_is_suppressed(ctxt, scope, die, type_is_private);
+	if (type_suppressed && type_is_private)
+	  // The type is suppressed because it's private.  If other
+	  // non-suppressed and declaration-only instances of this
+	  // type exist in the current corpus, then it means those
+	  // non-suppressed instances are opaque versions of the
+	  // suppressed private type.  Lets return one of these opaque
+	  // types then.
+	  result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
+	else if (!type_suppressed)
 	  {
 	    enum_type_decl_sptr e = build_enum_type(ctxt, die, scope,
 						    where_offset);
-- 
1.8.3.1

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 09/11] Support constructing opaque types for enums
  2020-06-10 11:59 ` [PATCH 09/11] Support constructing opaque types for enums Giuliano Procida
@ 2020-07-06 11:23   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:23 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> From: Dodji Seketeli <dodji@redhat.com>
>
> Now that we are to support opaque types for enums, we ought to support
> building opaque types for enums as well, to mimic the opaque type
> design pattern used in C, when private types are specified with type
> suppression specifications.
>
> The core of this change is to make get_opaque_version_of_type work for
> enums as well, just like what it does for classes.  Note that that
> function doesn't support opaque unions yet either.  That should be
> added at a later point in time, I guess.
>
> 	* src/abg-dwarf-reader.cc
> 	(build_internal_underlying_enum_type_name)
> 	(build_enum_underlying_type): Factorize these functions out of ...
> 	(build_enum_type): ... here.
> 	(get_opaque_version_of_type): Make this handle enums as well.  So
> 	make its return type be type_or_decl_base_sptr, rather than just
> 	class_or_union_sptr as it used to be.

This patch is now fused with the previous one in the series so I am
dropping it.

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 11/11] Add tests for declaration-only enums.
  2020-06-10 11:59 ` [PATCH 11/11] Add tests for declaration-only enums Giuliano Procida
@ 2020-07-06 11:26   ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:26 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> Signed-off-by: Giuliano Procida <gprocida@google.com>
> ---
>  tests/data/Makefile.am                         |   5 +++++
>  .../test-decl-enum-report.txt                  |  17 +++++++++++++++++
>  .../data/test-abidiff-exit/test-decl-enum-v0.c |   5 +++++
>  .../data/test-abidiff-exit/test-decl-enum-v0.o | Bin 0 -> 3048 bytes
>  .../data/test-abidiff-exit/test-decl-enum-v1.c |   5 +++++
>  .../data/test-abidiff-exit/test-decl-enum-v1.o | Bin 0 -> 3048 bytes
>  tests/test-abidiff-exit.cc                     |   9 +++++++++
>  7 files changed, 41 insertions(+)
>  create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-report.txt
>  create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.c
>  create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.o
>  create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.c
>  create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.o

I am adding more tests to this, essentially one without the --harmless
option to abidiff and also for the leaf reporter.  These were helpful in
catching some issues in the initial code.

I am adding the updated patch below, along with a ChangeLog in the
commit log.

Cheers,

From 9d713aca269e4acdd2754be4fbcce0643c6a9e63 Mon Sep 17 00:00:00 2001
From: Giuliano Procida <gprocida@google.com>
Date: Wed, 10 Jun 2020 12:59:40 +0100
Subject: [PATCH 4/4] Add tests for declaration-only enums.

	* tests/data/test-abidiff-exit/test-decl-enum-report-2.txt: Add
	new test reference output.
	* tests/data/test-abidiff-exit/test-decl-enum-report-3.txt: Likewise.
	* tests/data/test-abidiff-exit/test-decl-enum-report.txt: Likewise.
	* tests/data/test-abidiff-exit/test-decl-enum-v{0,1}.c: Add source
	code for the binaries below.
	* tests/data/test-abidiff-exit/test-decl-enum-v{0,1}.o: Add new
	binary test inputs.
	* tests/data/Makefile.am: Add the new files above to source
	distribution.
	* tests/test-abidiff-exit.cc: Add the test inputs above to the
	test harness.

Signed-off-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 tests/data/Makefile.am                             |   7 ++++++
 .../test-abidiff-exit/test-decl-enum-report-2.txt  |   3 +++
 .../test-abidiff-exit/test-decl-enum-report-3.txt  |   5 ++++
 .../test-abidiff-exit/test-decl-enum-report.txt    |  17 +++++++++++++
 tests/data/test-abidiff-exit/test-decl-enum-v0.c   |   5 ++++
 tests/data/test-abidiff-exit/test-decl-enum-v0.o   | Bin 0 -> 3048 bytes
 tests/data/test-abidiff-exit/test-decl-enum-v1.c   |   5 ++++
 tests/data/test-abidiff-exit/test-decl-enum-v1.o   | Bin 0 -> 3048 bytes
 tests/test-abidiff-exit.cc                         |  27 +++++++++++++++++++++
 9 files changed, 69 insertions(+)
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-report-3.txt
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-report.txt
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.c
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.c
 create mode 100644 tests/data/test-abidiff-exit/test-decl-enum-v1.o

diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 8ccd50a..5da9ef9 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -158,6 +158,13 @@ test-abidiff-exit/test-fun-param-v0.o \
 test-abidiff-exit/test-fun-param-v1.abi \
 test-abidiff-exit/test-fun-param-v1.c \
 test-abidiff-exit/test-fun-param-v1.o \
+test-abidiff-exit/test-decl-enum-v0.c \
+test-abidiff-exit/test-decl-enum-v0.o \
+test-abidiff-exit/test-decl-enum-v1.c \
+test-abidiff-exit/test-decl-enum-v1.o \
+test-abidiff-exit/test-decl-enum-report.txt \
+test-abidiff-exit/test-decl-enum-report-2.txt \
+test-abidiff-exit/test-decl-enum-report-3.txt \
 \
 test-diff-dwarf/test0-v0.cc		\
 test-diff-dwarf/test0-v0.o			\
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-report-2.txt b/tests/data/test-abidiff-exit/test-decl-enum-report-2.txt
new file mode 100644
index 0000000..41fc64d
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-report-2.txt
@@ -0,0 +1,3 @@
+Functions changes summary: 0 Removed, 0 Changed (2 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-report-3.txt b/tests/data/test-abidiff-exit/test-decl-enum-report-3.txt
new file mode 100644
index 0000000..b5b84c7
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-report-3.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed
+Changed leaf types summary: 0 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-report.txt b/tests/data/test-abidiff-exit/test-decl-enum-report.txt
new file mode 100644
index 0000000..e46ebfa
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-report.txt
@@ -0,0 +1,17 @@
+Functions changes summary: 0 Removed, 2 Changed, 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C] 'function void reg1(const embodied_enum*)' at test-decl-enum-v1.c:4:1 has some indirect sub-type changes:
+    parameter 1 of type 'const embodied_enum*' has sub-type changes:
+      in pointed to type 'const embodied_enum':
+        in unqualified underlying type 'enum embodied_enum' at test-decl-enum-v1.c:1:1:
+          enum type enum embodied_enum was a declaration-only enum type and is now a defined enum type
+
+  [C] 'function void reg2(const disembodied_enum*)' at test-decl-enum-v1.c:5:1 has some indirect sub-type changes:
+    parameter 1 of type 'const disembodied_enum*' has sub-type changes:
+      in pointed to type 'const disembodied_enum':
+        in unqualified underlying type 'enum disembodied_enum':
+          enum type enum disembodied_enum was a defined enum type and is now a declaration-only enum type
+
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v0.c b/tests/data/test-abidiff-exit/test-decl-enum-v0.c
new file mode 100644
index 0000000..d567261
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-v0.c
@@ -0,0 +1,5 @@
+enum embodied_enum;
+enum disembodied_enum { X };
+
+void reg1(const enum embodied_enum * foo) { (void)foo; }
+void reg2(const enum disembodied_enum * foo) { (void)foo; }
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v0.o b/tests/data/test-abidiff-exit/test-decl-enum-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..b4c0b06a089ec6adbfa81b1a619ae30087e54f9d
GIT binary patch
literal 3048
zcmbtWUuzsy6hE^wo1Hk#Hp$xBG=+{(+eDplH%QIaCa$Ko2^OhB#TN;)J2$(7+1WBP
zTT?|XqC&xk3W5lt4}JmB7hejZzU!Cp!8d&qe9&`d?%CYjOcC_J+<VUN{GEH}oZWYy
zzk0c17{Fw}I_yh~0xZ?``A*JupaJu6ee=$*n|I#+^X_XuD(v@YVdYkK9_&cYE6Z_(
zuMl6ews18nQ<rcvU&Y1paH(2(-YI0ksOB574lPK==kMTJ+Zl~eyG(rL;{n(<1u1;2
z5}$7-KGxZL(q|fXEP_<F{T&I$obgD#;h6Qs`kXOen|%m_TZUO*cN}M{alv`oX*)&(
zi(LZKK7|!oXJHHF>KSmHb@am$eB+q~vtHPqTc9wV6Q4e}KyI}vx)qwOM&$&iJ&Jx5
zVA=x8a&ZBRcpRVne88rfCZwL<1VrX4J|;Yht6}_ApTRZ1Tf77VGLdFpD0;h|h{r?k
zX4CKGuGPn2y2ydzvFh>ns{R_T6%)P3aT@hw5xP;Fff#m2VI;zB@`o@=4+2+SyzXwa
zo^sp%ir;cqnyq%L)oi=oFdN5WtuJDcL_HLPq&HaGTRrccf712(uD27Ux8mL)8O5V<
z>W$+!qB!)jpt~#5(wY;|ZvieV@I*Ge0dQqw<AS?%NpzziE|Pn#_Oez+{-(G*C>i6;
zm%-SZH5QN5?7Mh8rx2%yDF3>it<Qc~*_fHSj0T92?jk9X%JhZi@JgS*1%Lc~SVI?;
zH^(8BDX&~tnCMYPrtCFcXBIu6!x%+rW<_g4-USL$u;!%S4ysI;IS5F}1pM|($b>_4
z0FI&EymAiQ*(W8=GVlNLMNHoK0ra1=KJuKIaC%E>ETXw$1IBMlnd%~9{EI>aYDyxy
zxk=L?zf2$!*{iMU=jeW%MJZFG5^?-O0(eO>jDIF&nutW4m(Sya0-nVAM9Lq@o$aLv
z-)i=JgM3z$x5~!2&q`j8)4mVxN}SF{J)e$-bN%3_w}#m4xMxYR517luUIu;`WC8fy
zGzC8qyMZ5y?zq1l#XBR^<$TcXCgSD+b&v#cALobavKz&MT`&dsz0q(eaIX3BC=))8
zFE7o4-s{py47PWYU?^na|8t{zr!(Yp=5QU!=mVW>ReBf&!t@F7ifW|ry8k)U(RcY@
z{afg($E0+e|0fa@(ru~V=pR8xu_5*s0+Cjw1AT7<aS!1SV@_+h>M==iQi9wExp9f@
zwGxbMzm)z>5){&Ny@0y1`fYik>`(R6bk*w*5z}KL1V2lV>QhO#-9}|u{#BWu&x!KW
zeADyaK#XEG@loltY|^h(5P8ne`&$yz{eO`D^nIzse!RbrO6FC&-_#+YD0EwzgM{hk
zze|AUBZuJkXPM?=+4)^7xj*{#Vt+o@vfLDVQ#RB<7EHe<G*fkdx)Z(k5Q49%D5TTH
UHd*!er?_SQw`KkJyFU*24@%k9)Bpeg

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v1.c b/tests/data/test-abidiff-exit/test-decl-enum-v1.c
new file mode 100644
index 0000000..046a55d
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-decl-enum-v1.c
@@ -0,0 +1,5 @@
+enum embodied_enum { Y };
+enum disembodied_enum;
+
+void reg1(const enum embodied_enum * foo) { (void)foo; }
+void reg2(const enum disembodied_enum * foo) { (void)foo; }
diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v1.o b/tests/data/test-abidiff-exit/test-decl-enum-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..e9c8d081a21e6d3806fb79661e4fb3c333cc442d
GIT binary patch
literal 3048
zcmbtVPj4GV6o2Dg#}3=LNlZ)ARO(hLZ35jTj!=n96AUSBA}Umnir|2vwRd8#h}YHb
zx}+f53YAK^1qrFDRKbBSz!yM5z#YB>2X1gf;sEc>&e)U5_5x4ZH}C!4-}$@u-n@Rb
z#26@Ium)pIp#Te&vD^}33+gZnH#hcv+t~Z;ul)~y(!?Lo!xmmuk?e?&HFjK+OC(q9
zP2`MCT*1Nm0GaI}E8C*(1d71QVj$5WhQyxSMPAt+4A8o`hjQu59#qLxvB@-9eSka<
zw+q6*Cr=S>pCg&VC#%#0uo?Dzt?pR0`PvMdtxP|MR-0M1HOFx_>zABYou<R;*z5vW
z)l=A!eGWEJFP{a+S;IK2>$BJ9tXl4SevZ<#PCR;Jj>0Ns49hK>_0kD|stuI<@*H-3
z6jM+xxIjHoH~FN5L`+}55s1Qd{496@Ib(m<rjU!h#Z6$4@ig;7-r4bZJnVb78-7QG
zmS2R)yauYr%Ev!1`>V)H7Df-_H0s7YbfY*cOb|vX@3#kG#KSF03)kMh>8>|kahv|K
z-*A_g8qG#ysp)$CY#8&^E{}N<bx;kGPH%O0<)U}-W!LMv-gc1Qi95Yy5D$i_H;g}y
z;?T>2_6|?sV1<Nt8-Q#XUdsBn0IsdCUvd|&@OBi$d0DT~Tr?UGGe!2S6xb*40^6Nt
z^G7PxeO#VXh|@<TPS@+T>4&BDsfnxTfEd{>lM$)No?8xcI{r5N`OjesZIrkihfJ2-
za?@a8L=jo?u9-F~Klmn$S+vWnSuL2<w6SQ7?%Nn6$%3hafYdC&vtK|K9C`=f82Zg>
z>!5D-Nr@|6jfIDBd?H3Oeg@-5_Z?+bnQ)rrGJZre`2Y%6GorqT6#jLt0^UwRv~#0N
zgYsey3xDzcNZr?Ps{2stbWw>^{#*liM+ypmEcN&0sOqZqxM%pEk@~)Ye<k%ta#VSw
zI$A5LTUH>B(^5A5n@_=AiPPHX>(erD)j#;@ojzW39J3@JdrHdqZU%lBWC8f?GzCB5
zJAoha_OQDZ#oGh42{~xD6Mp-EIY@%Ii!X;BvJ=Hzg<uKrJA;0o<Gbd^gN*z5aCvDK
zbUu<nytlQT1br?W|DVG=#?u<=XOdF3h#{E|I{E5!1{K207vMeJNt4a^^Jt@U`CsE3
z7;EOFa;pB%q-bRNUO=0TUrX~L@mB(oR%8I3H-gk1!XKlcRpe$)GMtp)7s6}IOy3)5
zGBNW0MuJP@P$8MVZy{RLe^qX%il_eRbv64B5i@fl1iwg-`qRnu-9lqg{S{eXtrOL!
zcgC!L3o**Mgr82Q<t6=A2T@k_)%dBz%=jN=Je@C{RGb<gpi#-X-|sSB$4EAP=^Z4@
zbpJyF>V2eGA~pY91EBY>X#H*!>>vHTRJ>Z(qS};uLtdz!Y?%Hh^baxPX-~|%hY);6
YO(C7mhY>gDPkD>t@5}z5wtp(&zdst)dH?_b

literal 0
HcmV?d00001

diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc
index 4d9c194..244de2a 100644
--- a/tests/test-abidiff-exit.cc
+++ b/tests/test-abidiff-exit.cc
@@ -212,6 +212,33 @@ InOutSpec in_out_specs[] =
     "data/test-abidiff-exit/test-fun-param-report.txt",
     "output/test-abidiff-exit/test-fun-param-report.txt"
   },
+  {
+    "data/test-abidiff-exit/test-decl-enum-v0.o",
+    "data/test-abidiff-exit/test-decl-enum-v1.o",
+    "",
+    "--harmless",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-decl-enum-report.txt",
+    "output/test-abidiff-exit/test-decl-enum-report.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-decl-enum-v0.o",
+    "data/test-abidiff-exit/test-decl-enum-v1.o",
+    "",
+    "",
+    abigail::tools_utils::ABIDIFF_OK,
+    "data/test-abidiff-exit/test-decl-enum-report-2.txt",
+    "output/test-abidiff-exit/test-decl-enum-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-decl-enum-v0.o",
+    "data/test-abidiff-exit/test-decl-enum-v1.o",
+    "",
+    "--leaf-changes-only",
+    abigail::tools_utils::ABIDIFF_OK,
+    "data/test-abidiff-exit/test-decl-enum-report-3.txt",
+    "output/test-abidiff-exit/test-decl-enum-report-3.txt"
+  },
   {0, 0, 0 ,0,  abigail::tools_utils::ABIDIFF_OK, 0, 0}
 };
 
-- 
1.8.3.1


>
> diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
> index 6592ba32..7b239682 100644
> --- a/tests/data/Makefile.am
> +++ b/tests/data/Makefile.am
> @@ -158,6 +158,11 @@ test-abidiff-exit/test-fun-param-v0.o \
>  test-abidiff-exit/test-fun-param-v1.abi \
>  test-abidiff-exit/test-fun-param-v1.c \
>  test-abidiff-exit/test-fun-param-v1.o \
> +test-abidiff-exit/test-decl-enum-v0.c \
> +test-abidiff-exit/test-decl-enum-v0.o \
> +test-abidiff-exit/test-decl-enum-v1.c \
> +test-abidiff-exit/test-decl-enum-v1.o \
> +test-abidiff-exit/test-decl-enum-report.txt \
>  \
>  test-diff-dwarf/test0-v0.cc		\
>  test-diff-dwarf/test0-v0.o			\
> diff --git a/tests/data/test-abidiff-exit/test-decl-enum-report.txt b/tests/data/test-abidiff-exit/test-decl-enum-report.txt
> new file mode 100644
> index 00000000..e46ebfa6
> --- /dev/null
> +++ b/tests/data/test-abidiff-exit/test-decl-enum-report.txt
> @@ -0,0 +1,17 @@
> +Functions changes summary: 0 Removed, 2 Changed, 0 Added functions
> +Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
> +
> +2 functions with some indirect sub-type change:
> +
> +  [C] 'function void reg1(const embodied_enum*)' at test-decl-enum-v1.c:4:1 has some indirect sub-type changes:
> +    parameter 1 of type 'const embodied_enum*' has sub-type changes:
> +      in pointed to type 'const embodied_enum':
> +        in unqualified underlying type 'enum embodied_enum' at test-decl-enum-v1.c:1:1:
> +          enum type enum embodied_enum was a declaration-only enum type and is now a defined enum type
> +
> +  [C] 'function void reg2(const disembodied_enum*)' at test-decl-enum-v1.c:5:1 has some indirect sub-type changes:
> +    parameter 1 of type 'const disembodied_enum*' has sub-type changes:
> +      in pointed to type 'const disembodied_enum':
> +        in unqualified underlying type 'enum disembodied_enum':
> +          enum type enum disembodied_enum was a defined enum type and is now a declaration-only enum type
> +
> diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v0.c b/tests/data/test-abidiff-exit/test-decl-enum-v0.c
> new file mode 100644
> index 00000000..d5672618
> --- /dev/null
> +++ b/tests/data/test-abidiff-exit/test-decl-enum-v0.c
> @@ -0,0 +1,5 @@
> +enum embodied_enum;
> +enum disembodied_enum { X };
> +
> +void reg1(const enum embodied_enum * foo) { (void)foo; }
> +void reg2(const enum disembodied_enum * foo) { (void)foo; }
> diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v0.o b/tests/data/test-abidiff-exit/test-decl-enum-v0.o
> new file mode 100644
> index 0000000000000000000000000000000000000000..b4c0b06a089ec6adbfa81b1a619ae30087e54f9d
> GIT binary patch
> literal 3048
> zcmbtWUuzsy6hE^wo1Hk#Hp$xBG=+{(+eDplH%QIaCa$Ko2^OhB#TN;)J2$(7+1WBP
> zTT?|XqC&xk3W5lt4}JmB7hejZzU!Cp!8d&qe9&`d?%CYjOcC_J+<VUN{GEH}oZWYy
> zzk0c17{Fw}I_yh~0xZ?``A*JupaJu6ee=$*n|I#+^X_XuD(v@YVdYkK9_&cYE6Z_(
> zuMl6ews18nQ<rcvU&Y1paH(2(-YI0ksOB574lPK==kMTJ+Zl~eyG(rL;{n(<1u1;2
> z5}$7-KGxZL(q|fXEP_<F{T&I$obgD#;h6Qs`kXOen|%m_TZUO*cN}M{alv`oX*)&(
> zi(LZKK7|!oXJHHF>KSmHb@am$eB+q~vtHPqTc9wV6Q4e}KyI}vx)qwOM&$&iJ&Jx5
> zVA=x8a&ZBRcpRVne88rfCZwL<1VrX4J|;Yht6}_ApTRZ1Tf77VGLdFpD0;h|h{r?k
> zX4CKGuGPn2y2ydzvFh>ns{R_T6%)P3aT@hw5xP;Fff#m2VI;zB@`o@=4+2+SyzXwa
> zo^sp%ir;cqnyq%L)oi=oFdN5WtuJDcL_HLPq&HaGTRrccf712(uD27Ux8mL)8O5V<
> z>W$+!qB!)jpt~#5(wY;|ZvieV@I*Ge0dQqw<AS?%NpzziE|Pn#_Oez+{-(G*C>i6;
> zm%-SZH5QN5?7Mh8rx2%yDF3>it<Qc~*_fHSj0T92?jk9X%JhZi@JgS*1%Lc~SVI?;
> zH^(8BDX&~tnCMYPrtCFcXBIu6!x%+rW<_g4-USL$u;!%S4ysI;IS5F}1pM|($b>_4
> z0FI&EymAiQ*(W8=GVlNLMNHoK0ra1=KJuKIaC%E>ETXw$1IBMlnd%~9{EI>aYDyxy
> zxk=L?zf2$!*{iMU=jeW%MJZFG5^?-O0(eO>jDIF&nutW4m(Sya0-nVAM9Lq@o$aLv
> z-)i=JgM3z$x5~!2&q`j8)4mVxN}SF{J)e$-bN%3_w}#m4xMxYR517luUIu;`WC8fy
> zGzC8qyMZ5y?zq1l#XBR^<$TcXCgSD+b&v#cALobavKz&MT`&dsz0q(eaIX3BC=))8
> zFE7o4-s{py47PWYU?^na|8t{zr!(Yp=5QU!=mVW>ReBf&!t@F7ifW|ry8k)U(RcY@
> z{afg($E0+e|0fa@(ru~V=pR8xu_5*s0+Cjw1AT7<aS!1SV@_+h>M==iQi9wExp9f@
> zwGxbMzm)z>5){&Ny@0y1`fYik>`(R6bk*w*5z}KL1V2lV>QhO#-9}|u{#BWu&x!KW
> zeADyaK#XEG@loltY|^h(5P8ne`&$yz{eO`D^nIzse!RbrO6FC&-_#+YD0EwzgM{hk
> zze|AUBZuJkXPM?=+4)^7xj*{#Vt+o@vfLDVQ#RB<7EHe<G*fkdx)Z(k5Q49%D5TTH
> UHd*!er?_SQw`KkJyFU*24@%k9)Bpeg
>
> literal 0
> HcmV?d00001
>
> diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v1.c b/tests/data/test-abidiff-exit/test-decl-enum-v1.c
> new file mode 100644
> index 00000000..046a55d3
> --- /dev/null
> +++ b/tests/data/test-abidiff-exit/test-decl-enum-v1.c
> @@ -0,0 +1,5 @@
> +enum embodied_enum { Y };
> +enum disembodied_enum;
> +
> +void reg1(const enum embodied_enum * foo) { (void)foo; }
> +void reg2(const enum disembodied_enum * foo) { (void)foo; }
> diff --git a/tests/data/test-abidiff-exit/test-decl-enum-v1.o b/tests/data/test-abidiff-exit/test-decl-enum-v1.o
> new file mode 100644
> index 0000000000000000000000000000000000000000..e9c8d081a21e6d3806fb79661e4fb3c333cc442d
> GIT binary patch
> literal 3048
> zcmbtVPj4GV6o2Dg#}3=LNlZ)ARO(hLZ35jTj!=n96AUSBA}Umnir|2vwRd8#h}YHb
> zx}+f53YAK^1qrFDRKbBSz!yM5z#YB>2X1gf;sEc>&e)U5_5x4ZH}C!4-}$@u-n@Rb
> z#26@Ium)pIp#Te&vD^}33+gZnH#hcv+t~Z;ul)~y(!?Lo!xmmuk?e?&HFjK+OC(q9
> zP2`MCT*1Nm0GaI}E8C*(1d71QVj$5WhQyxSMPAt+4A8o`hjQu59#qLxvB@-9eSka<
> zw+q6*Cr=S>pCg&VC#%#0uo?Dzt?pR0`PvMdtxP|MR-0M1HOFx_>zABYou<R;*z5vW
> z)l=A!eGWEJFP{a+S;IK2>$BJ9tXl4SevZ<#PCR;Jj>0Ns49hK>_0kD|stuI<@*H-3
> z6jM+xxIjHoH~FN5L`+}55s1Qd{496@Ib(m<rjU!h#Z6$4@ig;7-r4bZJnVb78-7QG
> zmS2R)yauYr%Ev!1`>V)H7Df-_H0s7YbfY*cOb|vX@3#kG#KSF03)kMh>8>|kahv|K
> z-*A_g8qG#ysp)$CY#8&^E{}N<bx;kGPH%O0<)U}-W!LMv-gc1Qi95Yy5D$i_H;g}y
> z;?T>2_6|?sV1<Nt8-Q#XUdsBn0IsdCUvd|&@OBi$d0DT~Tr?UGGe!2S6xb*40^6Nt
> z^G7PxeO#VXh|@<TPS@+T>4&BDsfnxTfEd{>lM$)No?8xcI{r5N`OjesZIrkihfJ2-
> za?@a8L=jo?u9-F~Klmn$S+vWnSuL2<w6SQ7?%Nn6$%3hafYdC&vtK|K9C`=f82Zg>
> z>!5D-Nr@|6jfIDBd?H3Oeg@-5_Z?+bnQ)rrGJZre`2Y%6GorqT6#jLt0^UwRv~#0N
> zgYsey3xDzcNZr?Ps{2stbWw>^{#*liM+ypmEcN&0sOqZqxM%pEk@~)Ye<k%ta#VSw
> zI$A5LTUH>B(^5A5n@_=AiPPHX>(erD)j#;@ojzW39J3@JdrHdqZU%lBWC8f?GzCB5
> zJAoha_OQDZ#oGh42{~xD6Mp-EIY@%Ii!X;BvJ=Hzg<uKrJA;0o<Gbd^gN*z5aCvDK
> zbUu<nytlQT1br?W|DVG=#?u<=XOdF3h#{E|I{E5!1{K207vMeJNt4a^^Jt@U`CsE3
> z7;EOFa;pB%q-bRNUO=0TUrX~L@mB(oR%8I3H-gk1!XKlcRpe$)GMtp)7s6}IOy3)5
> zGBNW0MuJP@P$8MVZy{RLe^qX%il_eRbv64B5i@fl1iwg-`qRnu-9lqg{S{eXtrOL!
> zcgC!L3o**Mgr82Q<t6=A2T@k_)%dBz%=jN=Je@C{RGb<gpi#-X-|sSB$4EAP=^Z4@
> zbpJyF>V2eGA~pY91EBY>X#H*!>>vHTRJ>Z(qS};uLtdz!Y?%Hh^baxPX-~|%hY);6
> YO(C7mhY>gDPkD>t@5}z5wtp(&zdst)dH?_b
>
> literal 0
> HcmV?d00001
>
> diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc
> index 4d9c1943..4fc1eec7 100644
> --- a/tests/test-abidiff-exit.cc
> +++ b/tests/test-abidiff-exit.cc
> @@ -212,6 +212,15 @@ InOutSpec in_out_specs[] =
>      "data/test-abidiff-exit/test-fun-param-report.txt",
>      "output/test-abidiff-exit/test-fun-param-report.txt"
>    },
> +  {
> +    "data/test-abidiff-exit/test-decl-enum-v0.o",
> +    "data/test-abidiff-exit/test-decl-enum-v1.o",
> +    "",
> +    "--harmless",
> +    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
> +    "data/test-abidiff-exit/test-decl-enum-report.txt",
> +    "output/test-abidiff-exit/test-decl-enum-report.txt"
> +  },
>    {0, 0, 0 ,0,  abigail::tools_utils::ABIDIFF_OK, 0, 0}
>  };

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-06-10 11:59 ` [PATCH 10/11] Add declaration-only enums to XML reader/writer Giuliano Procida
  2020-07-02 13:55   ` Dodji Seketeli
@ 2020-07-06 11:31   ` Dodji Seketeli
  2020-07-07  8:31     ` Giuliano Procida
  1 sibling, 1 reply; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-06 11:31 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

> Serialisation seems OK.
>
> Deserialisation quite likely needs declaration/definition resolution
> as there is logic for this for class types.

I have amended this patch to make it work in the context of the changes
I have done on the earlier patches of the series.  Namely, the
decl-only-ness property can now show up on any declaration, not just on
classes, unions and enums.  I have also added a ChangeLog in the commit
log.

I had to update a test reference output to reflect the new format.

The amended patch below is also stacked up in the dodji/incomp-enums
branch, browsable at
https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/dodji/incomp-enums.

Cheers,

From 1469056ef52e5c2f44b276b5f058496a3416a716 Mon Sep 17 00:00:00 2001
From: Giuliano Procida <gprocida@google.com>
Date: Wed, 10 Jun 2020 12:59:39 +0100
Subject: [PATCH 3/4] Add declaration-only enums to XML reader/writer.

	* src/abg-reader.cc (build_enum_type_decl): Detect a
	declaration-only enum and flag it as such.
	(build_type_decl): Support reading the "is-declaration" attribute.
	(build_class_decl): Adjust.
	* src/abg-writer.cc (write_is_declaration_only): Renamed
	write_class_or_union_is_declaration_only into this.
	(write_enum_is_declaration_only): Remove.
	(write_type_decl, write_enum_type_decl)
	(write_class_decl_opening_tag, write_union_decl_opening_tag): Use
	write_is_declaration_only.
	* tests/data/test-read-dwarf/PR22122-libftdc.so.abi: Adjust.

Signed-off-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 src/abg-reader.cc                                 | 13 ++++++--
 src/abg-writer.cc                                 | 22 +++++++-------
 tests/data/test-read-dwarf/PR22122-libftdc.so.abi | 36 +++++++++++------------
 3 files changed, 39 insertions(+), 32 deletions(-)

diff --git a/src/abg-reader.cc b/src/abg-reader.cc
index eb74659..6e37f7c 100644
--- a/src/abg-reader.cc
+++ b/src/abg-reader.cc
@@ -3457,6 +3457,9 @@ build_type_decl(read_context&		ctxt,
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "alignment-in-bits"))
     alignment_in_bits = atoi(CHAR_STR(s));
 
+  bool is_decl_only = false;
+  read_is_declaration_only(node, is_decl_only);
+
   location loc;
   read_location(ctxt, node, loc);
 
@@ -3479,6 +3482,7 @@ build_type_decl(read_context&		ctxt,
   type_decl_sptr decl(new type_decl(env, name, size_in_bits,
 				    alignment_in_bits, loc));
   decl->set_is_anonymous(is_anonymous);
+  decl->set_is_declaration_only(is_decl_only);
   if (ctxt.push_and_key_type_decl(decl, id, add_to_current_scope))
     {
       ctxt.map_xml_node_to_decl(node, decl);
@@ -4161,6 +4165,9 @@ build_enum_type_decl(read_context&	ctxt,
   location loc;
   read_location(ctxt, node, loc);
 
+  bool is_decl_only = false;
+  read_is_declaration_only(node, is_decl_only);
+
   bool is_anonymous = false;
   read_is_anonymous(node, is_anonymous);
 
@@ -4221,6 +4228,7 @@ build_enum_type_decl(read_context&	ctxt,
 					   enums, linkage_name));
   t->set_is_anonymous(is_anonymous);
   t->set_is_artificial(is_artificial);
+  t->set_is_declaration_only(is_decl_only); // TODO: more to do here!
   if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
     {
       ctxt.map_xml_node_to_decl(node, t);
@@ -4488,8 +4496,7 @@ build_class_decl(read_context&		ctxt,
 
   if (!def_id.empty())
     {
-      class_decl_sptr d =
-	dynamic_pointer_cast<class_decl>(ctxt.get_type_decl(def_id));
+      decl_base_sptr d = is_decl(ctxt.get_type_decl(def_id));
       if (d && d->get_is_declaration_only())
 	{
 	  is_def_of_decl = true;
@@ -4507,7 +4514,7 @@ build_class_decl(read_context&		ctxt,
       // previous_declaration.
       //
       // Let's link them.
-      decl->set_earlier_declaration(previous_declaration);
+      decl->set_earlier_declaration(is_decl(previous_declaration));
       for (vector<type_base_sptr>::const_iterator i = types_ptr->begin();
 	   i != types_ptr->end();
 	   ++i)
diff --git a/src/abg-writer.cc b/src/abg-writer.cc
index ce0bae2..bf44c76 100644
--- a/src/abg-writer.cc
+++ b/src/abg-writer.cc
@@ -876,8 +876,7 @@ static void write_elf_symbol_binding(elf_symbol::binding, ostream&);
 static bool write_elf_symbol_aliases(const elf_symbol&, ostream&);
 static bool write_elf_symbol_reference(const elf_symbol&, ostream&);
 static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&);
-static void write_class_or_union_is_declaration_only(const class_or_union_sptr&,
-						     ostream&);
+static void write_is_declaration_only(const decl_base_sptr&, ostream&);
 static void write_is_struct(const class_decl_sptr&, ostream&);
 static void write_is_anonymous(const decl_base_sptr&, ostream&);
 static void write_naming_typedef(const class_decl_sptr&, write_context&);
@@ -1777,18 +1776,16 @@ write_cdtor_const_static(bool is_ctor,
     o << " const='yes'";
 }
 
-/// Serialize the attribute "is-declaration-only", if the class or
-/// union has its 'is_declaration_only property set.
+/// Serialize the attribute "is-declaration-only", if the
+/// decl_base_sptr has its 'is_declaration_only property set.
 ///
-/// @param t the pointer to instance of @ref class_or_union to
-/// consider.
+/// @param t the pointer to instance of @ref decl_base to consider.
 ///
 /// @param o the output stream to serialize to.
 static void
-write_class_or_union_is_declaration_only(const class_or_union_sptr& t,
-					 ostream& o)
+write_is_declaration_only(const decl_base_sptr& d, ostream& o)
 {
-  if (t->get_is_declaration_only())
+  if (d->get_is_declaration_only())
     o << " is-declaration-only='yes'";
 }
 
@@ -2459,6 +2456,8 @@ write_type_decl(const type_decl_sptr& d, write_context& ctxt, unsigned indent)
 
   write_size_and_alignment(d, o);
 
+  write_is_declaration_only(d, o);
+
   write_location(d, ctxt);
 
   o << " id='" << ctxt.get_id_for_type(d) << "'" <<  "/>";
@@ -2938,6 +2937,7 @@ write_enum_type_decl(const enum_type_decl_sptr& decl,
     o << " linkage-name='" << decl->get_linkage_name() << "'";
 
   write_location(decl, ctxt);
+  write_is_declaration_only(decl, o);
 
   string i = id;
   if (i.empty())
@@ -3475,7 +3475,7 @@ write_class_decl_opening_tag(const class_decl_sptr&	decl,
 
   write_location(decl, ctxt);
 
-  write_class_or_union_is_declaration_only(decl, o);
+  write_is_declaration_only(decl, o);
 
   if (decl->get_earlier_declaration())
     {
@@ -3549,7 +3549,7 @@ write_union_decl_opening_tag(const union_decl_sptr&	decl,
 
   write_location(decl, ctxt);
 
-  write_class_or_union_is_declaration_only(decl, o);
+  write_is_declaration_only(decl, o);
 
   string i = id;
   if (i.empty())
diff --git a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
index 28df268..7ea5341 100644
--- a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
+++ b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
@@ -270,7 +270,7 @@
     <type-decl name='long long int' size-in-bits='64' id='type-id-16'/>
     <type-decl name='long long unsigned int' size-in-bits='64' id='type-id-17'/>
     <type-decl name='sizetype' size-in-bits='64' id='type-id-5'/>
-    <type-decl name='unnamed-enum-underlying-type' is-anonymous='yes' id='type-id-18'/>
+    <type-decl name='unnamed-enum-underlying-type' is-anonymous='yes' is-declaration-only='yes' id='type-id-18'/>
     <type-decl name='unsigned char' size-in-bits='8' id='type-id-19'/>
     <type-decl name='unsigned int' size-in-bits='32' id='type-id-20'/>
     <type-decl name='unsigned long int' size-in-bits='64' id='type-id-21'/>
@@ -500,7 +500,7 @@
         <class-decl name='basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;' size-in-bits='256' visibility='default' is-declaration-only='yes' id='type-id-92'>
 
             <member-type access='private'>
-              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-150'>
+              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-150'>
                 <underlying-type type-id='type-id-18'/>
               </enum-decl>
             </member-type>
@@ -969,7 +969,7 @@
           </function-decl>
         </member-function>
       </class-decl>
-      <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-172'>
+      <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-172'>
         <underlying-type type-id='type-id-18'/>
       </enum-decl>
       <typedef-decl name='memory_order' type-id='type-id-172' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/atomic_base.h' line='63' column='1' id='type-id-171'/>
@@ -1140,7 +1140,7 @@
       <class-decl name='__anonymous_struct__2' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-32'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-184'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-184'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -3878,7 +3878,7 @@
       <class-decl name='__anonymous_struct__17' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-232'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-240'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-240'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -4401,7 +4401,7 @@
       <class-decl name='__anonymous_struct__6' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-174'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-255'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-255'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -5356,7 +5356,7 @@
         <class-decl name='__anonymous_struct__3' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-57'>
 
             <member-type access='private'>
-              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-337'>
+              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-337'>
                 <underlying-type type-id='type-id-18'/>
               </enum-decl>
             </member-type>
@@ -5409,7 +5409,7 @@
       <class-decl name='__anonymous_struct__1' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-28'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-338'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-338'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -5427,7 +5427,7 @@
       <class-decl name='__anonymous_struct__8' is-anonymous='yes' naming-typedef-id='type-id-334' visibility='default' is-declaration-only='yes' id='type-id-175'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-339'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-339'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -7103,14 +7103,14 @@
         <class-decl name='__anonymous_struct__2' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-32'>
 
             <member-type access='private'>
-              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-402'>
+              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-402'>
                 <underlying-type type-id='type-id-18'/>
               </enum-decl>
             </member-type>
         </class-decl>
       </namespace-decl>
       <namespace-decl name='FTDCBSONUtil'>
-        <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-383'>
+        <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-383'>
           <underlying-type type-id='type-id-18'/>
         </enum-decl>
       </namespace-decl>
@@ -7272,7 +7272,7 @@
       <class-decl name='__anonymous_struct__19' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-234'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-403'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-403'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -7456,7 +7456,7 @@
           <class-decl name='__anonymous_struct__1' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-28'/>
         </member-type>
       </class-decl>
-      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' id='type-id-426'>
+      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' is-declaration-only='yes' id='type-id-426'>
         <underlying-type type-id='type-id-18'/>
       </enum-decl>
       <typedef-decl name='streamsize' type-id='type-id-163' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/postypes.h' line='98' column='1' id='type-id-181'/>
@@ -7905,7 +7905,7 @@
         <class-decl name='__anonymous_struct__' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-24'>
 
             <member-type access='private'>
-              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-432'>
+              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-432'>
                 <underlying-type type-id='type-id-18'/>
               </enum-decl>
             </member-type>
@@ -7986,7 +7986,7 @@
       <class-decl name='__anonymous_struct__11' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-186'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-433'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-433'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
@@ -8680,7 +8680,7 @@
           </function-decl>
         </member-function>
       </class-decl>
-      <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-459'>
+      <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-459'>
         <underlying-type type-id='type-id-18'/>
       </enum-decl>
       <class-decl name='__anonymous_struct__14' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-229'/>
@@ -8809,7 +8809,7 @@
           </function-decl>
         </member-function>
       </class-decl>
-      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' id='type-id-460'>
+      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' is-declaration-only='yes' id='type-id-460'>
         <underlying-type type-id='type-id-18'/>
       </enum-decl>
       <class-decl name='__anonymous_struct__23' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-220'>
@@ -8864,7 +8864,7 @@
       <class-decl name='__anonymous_struct__26' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-308'>
 
           <member-type access='private'>
-            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-461'>
+            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-461'>
               <underlying-type type-id='type-id-18'/>
             </enum-decl>
           </member-type>
-- 
1.8.3.1


-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-07-06 11:31   ` Dodji Seketeli
@ 2020-07-07  8:31     ` Giuliano Procida
  2020-07-07 14:57       ` Dodji Seketeli
  0 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-07-07  8:31 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail, kernel-team

Hi there.

On Mon, 6 Jul 2020 at 12:31, Dodji Seketeli <dodji@seketeli.org> wrote:
>
> Giuliano Procida <gprocida@google.com> a écrit:
>
> > Serialisation seems OK.
> >
> > Deserialisation quite likely needs declaration/definition resolution
> > as there is logic for this for class types.
>
> I have amended this patch to make it work in the context of the changes
> I have done on the earlier patches of the series.  Namely, the
> decl-only-ness property can now show up on any declaration, not just on
> classes, unions and enums.  I have also added a ChangeLog in the commit
> log.
>
> I had to update a test reference output to reflect the new format.
>
> The amended patch below is also stacked up in the dodji/incomp-enums
> branch, browsable at
> https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/dodji/incomp-enums.
>
> Cheers,
>
> From 1469056ef52e5c2f44b276b5f058496a3416a716 Mon Sep 17 00:00:00 2001
> From: Giuliano Procida <gprocida@google.com>
> Date: Wed, 10 Jun 2020 12:59:39 +0100
> Subject: [PATCH 3/4] Add declaration-only enums to XML reader/writer.
>
>         * src/abg-reader.cc (build_enum_type_decl): Detect a
>         declaration-only enum and flag it as such.
>         (build_type_decl): Support reading the "is-declaration" attribute.
>         (build_class_decl): Adjust.
>         * src/abg-writer.cc (write_is_declaration_only): Renamed
>         write_class_or_union_is_declaration_only into this.
>         (write_enum_is_declaration_only): Remove.
>         (write_type_decl, write_enum_type_decl)
>         (write_class_decl_opening_tag, write_union_decl_opening_tag): Use
>         write_is_declaration_only.
>         * tests/data/test-read-dwarf/PR22122-libftdc.so.abi: Adjust.
>
> Signed-off-by: Giuliano Procida <gprocida@google.com>
> Signed-off-by: Dodji Seketeli <dodji@redhat.com>
> ---
>  src/abg-reader.cc                                 | 13 ++++++--
>  src/abg-writer.cc                                 | 22 +++++++-------
>  tests/data/test-read-dwarf/PR22122-libftdc.so.abi | 36 +++++++++++------------
>  3 files changed, 39 insertions(+), 32 deletions(-)
>
> diff --git a/src/abg-reader.cc b/src/abg-reader.cc
> index eb74659..6e37f7c 100644
> --- a/src/abg-reader.cc
> +++ b/src/abg-reader.cc
> @@ -3457,6 +3457,9 @@ build_type_decl(read_context&             ctxt,
>    if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "alignment-in-bits"))
>      alignment_in_bits = atoi(CHAR_STR(s));
>
> +  bool is_decl_only = false;
> +  read_is_declaration_only(node, is_decl_only);
> +
>    location loc;
>    read_location(ctxt, node, loc);
>
> @@ -3479,6 +3482,7 @@ build_type_decl(read_context&             ctxt,
>    type_decl_sptr decl(new type_decl(env, name, size_in_bits,
>                                     alignment_in_bits, loc));
>    decl->set_is_anonymous(is_anonymous);
> +  decl->set_is_declaration_only(is_decl_only);
>    if (ctxt.push_and_key_type_decl(decl, id, add_to_current_scope))
>      {
>        ctxt.map_xml_node_to_decl(node, decl);
> @@ -4161,6 +4165,9 @@ build_enum_type_decl(read_context&        ctxt,
>    location loc;
>    read_location(ctxt, node, loc);
>
> +  bool is_decl_only = false;
> +  read_is_declaration_only(node, is_decl_only);
> +
>    bool is_anonymous = false;
>    read_is_anonymous(node, is_anonymous);
>
> @@ -4221,6 +4228,7 @@ build_enum_type_decl(read_context&        ctxt,
>                                            enums, linkage_name));
>    t->set_is_anonymous(is_anonymous);
>    t->set_is_artificial(is_artificial);
> +  t->set_is_declaration_only(is_decl_only); // TODO: more to do here!

I think this TODO was related to resolution and is dead.
(Note to self: write better TODO text.)

>    if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
>      {
>        ctxt.map_xml_node_to_decl(node, t);
> @@ -4488,8 +4496,7 @@ build_class_decl(read_context&            ctxt,
>
>    if (!def_id.empty())
>      {
> -      class_decl_sptr d =
> -       dynamic_pointer_cast<class_decl>(ctxt.get_type_decl(def_id));
> +      decl_base_sptr d = is_decl(ctxt.get_type_decl(def_id));
>        if (d && d->get_is_declaration_only())
>         {
>           is_def_of_decl = true;
> @@ -4507,7 +4514,7 @@ build_class_decl(read_context&            ctxt,
>        // previous_declaration.
>        //
>        // Let's link them.
> -      decl->set_earlier_declaration(previous_declaration);
> +      decl->set_earlier_declaration(is_decl(previous_declaration));
>        for (vector<type_base_sptr>::const_iterator i = types_ptr->begin();
>            i != types_ptr->end();
>            ++i)
> diff --git a/src/abg-writer.cc b/src/abg-writer.cc
> index ce0bae2..bf44c76 100644
> --- a/src/abg-writer.cc
> +++ b/src/abg-writer.cc
> @@ -876,8 +876,7 @@ static void write_elf_symbol_binding(elf_symbol::binding, ostream&);
>  static bool write_elf_symbol_aliases(const elf_symbol&, ostream&);
>  static bool write_elf_symbol_reference(const elf_symbol&, ostream&);
>  static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&);
> -static void write_class_or_union_is_declaration_only(const class_or_union_sptr&,
> -                                                    ostream&);
> +static void write_is_declaration_only(const decl_base_sptr&, ostream&);
>  static void write_is_struct(const class_decl_sptr&, ostream&);
>  static void write_is_anonymous(const decl_base_sptr&, ostream&);
>  static void write_naming_typedef(const class_decl_sptr&, write_context&);
> @@ -1777,18 +1776,16 @@ write_cdtor_const_static(bool is_ctor,
>      o << " const='yes'";
>  }
>
> -/// Serialize the attribute "is-declaration-only", if the class or
> -/// union has its 'is_declaration_only property set.
> +/// Serialize the attribute "is-declaration-only", if the
> +/// decl_base_sptr has its 'is_declaration_only property set.
>  ///
> -/// @param t the pointer to instance of @ref class_or_union to
> -/// consider.
> +/// @param t the pointer to instance of @ref decl_base to consider.
>  ///
>  /// @param o the output stream to serialize to.
>  static void
> -write_class_or_union_is_declaration_only(const class_or_union_sptr& t,
> -                                        ostream& o)
> +write_is_declaration_only(const decl_base_sptr& d, ostream& o)
>  {
> -  if (t->get_is_declaration_only())
> +  if (d->get_is_declaration_only())
>      o << " is-declaration-only='yes'";
>  }
>
> @@ -2459,6 +2456,8 @@ write_type_decl(const type_decl_sptr& d, write_context& ctxt, unsigned indent)
>
>    write_size_and_alignment(d, o);
>
> +  write_is_declaration_only(d, o);
> +
>    write_location(d, ctxt);
>
>    o << " id='" << ctxt.get_id_for_type(d) << "'" <<  "/>";
> @@ -2938,6 +2937,7 @@ write_enum_type_decl(const enum_type_decl_sptr& decl,
>      o << " linkage-name='" << decl->get_linkage_name() << "'";
>
>    write_location(decl, ctxt);
> +  write_is_declaration_only(decl, o);
>
>    string i = id;
>    if (i.empty())
> @@ -3475,7 +3475,7 @@ write_class_decl_opening_tag(const class_decl_sptr&       decl,
>
>    write_location(decl, ctxt);
>
> -  write_class_or_union_is_declaration_only(decl, o);
> +  write_is_declaration_only(decl, o);
>
>    if (decl->get_earlier_declaration())
>      {
> @@ -3549,7 +3549,7 @@ write_union_decl_opening_tag(const union_decl_sptr&       decl,
>
>    write_location(decl, ctxt);
>
> -  write_class_or_union_is_declaration_only(decl, o);
> +  write_is_declaration_only(decl, o);
>
>    string i = id;
>    if (i.empty())
> diff --git a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
> index 28df268..7ea5341 100644
> --- a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
> +++ b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
> @@ -270,7 +270,7 @@
>      <type-decl name='long long int' size-in-bits='64' id='type-id-16'/>
>      <type-decl name='long long unsigned int' size-in-bits='64' id='type-id-17'/>
>      <type-decl name='sizetype' size-in-bits='64' id='type-id-5'/>
> -    <type-decl name='unnamed-enum-underlying-type' is-anonymous='yes' id='type-id-18'/>
> +    <type-decl name='unnamed-enum-underlying-type' is-anonymous='yes' is-declaration-only='yes' id='type-id-18'/>
>      <type-decl name='unsigned char' size-in-bits='8' id='type-id-19'/>
>      <type-decl name='unsigned int' size-in-bits='32' id='type-id-20'/>
>      <type-decl name='unsigned long int' size-in-bits='64' id='type-id-21'/>
> @@ -500,7 +500,7 @@
>          <class-decl name='basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;' size-in-bits='256' visibility='default' is-declaration-only='yes' id='type-id-92'>
>
>              <member-type access='private'>
> -              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-150'>
> +              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-150'>
>                  <underlying-type type-id='type-id-18'/>
>                </enum-decl>
>              </member-type>
> @@ -969,7 +969,7 @@
>            </function-decl>
>          </member-function>
>        </class-decl>
> -      <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-172'>
> +      <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-172'>
>          <underlying-type type-id='type-id-18'/>
>        </enum-decl>
>        <typedef-decl name='memory_order' type-id='type-id-172' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/atomic_base.h' line='63' column='1' id='type-id-171'/>
> @@ -1140,7 +1140,7 @@
>        <class-decl name='__anonymous_struct__2' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-32'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-184'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-184'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -3878,7 +3878,7 @@
>        <class-decl name='__anonymous_struct__17' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-232'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-240'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-240'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -4401,7 +4401,7 @@
>        <class-decl name='__anonymous_struct__6' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-174'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-255'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-255'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -5356,7 +5356,7 @@
>          <class-decl name='__anonymous_struct__3' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-57'>
>
>              <member-type access='private'>
> -              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-337'>
> +              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-337'>
>                  <underlying-type type-id='type-id-18'/>
>                </enum-decl>
>              </member-type>
> @@ -5409,7 +5409,7 @@
>        <class-decl name='__anonymous_struct__1' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-28'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-338'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-338'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -5427,7 +5427,7 @@
>        <class-decl name='__anonymous_struct__8' is-anonymous='yes' naming-typedef-id='type-id-334' visibility='default' is-declaration-only='yes' id='type-id-175'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-339'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-339'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -7103,14 +7103,14 @@
>          <class-decl name='__anonymous_struct__2' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-32'>
>
>              <member-type access='private'>
> -              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-402'>
> +              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-402'>
>                  <underlying-type type-id='type-id-18'/>
>                </enum-decl>
>              </member-type>
>          </class-decl>
>        </namespace-decl>
>        <namespace-decl name='FTDCBSONUtil'>
> -        <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-383'>
> +        <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-383'>
>            <underlying-type type-id='type-id-18'/>
>          </enum-decl>
>        </namespace-decl>
> @@ -7272,7 +7272,7 @@
>        <class-decl name='__anonymous_struct__19' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-234'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-403'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-403'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -7456,7 +7456,7 @@
>            <class-decl name='__anonymous_struct__1' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-28'/>
>          </member-type>
>        </class-decl>
> -      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' id='type-id-426'>
> +      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' is-declaration-only='yes' id='type-id-426'>
>          <underlying-type type-id='type-id-18'/>
>        </enum-decl>
>        <typedef-decl name='streamsize' type-id='type-id-163' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/postypes.h' line='98' column='1' id='type-id-181'/>
> @@ -7905,7 +7905,7 @@
>          <class-decl name='__anonymous_struct__' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-24'>
>
>              <member-type access='private'>
> -              <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-432'>
> +              <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-432'>
>                  <underlying-type type-id='type-id-18'/>
>                </enum-decl>
>              </member-type>
> @@ -7986,7 +7986,7 @@
>        <class-decl name='__anonymous_struct__11' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-186'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-433'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-433'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> @@ -8680,7 +8680,7 @@
>            </function-decl>
>          </member-function>
>        </class-decl>
> -      <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-459'>
> +      <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-459'>
>          <underlying-type type-id='type-id-18'/>
>        </enum-decl>
>        <class-decl name='__anonymous_struct__14' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-229'/>
> @@ -8809,7 +8809,7 @@
>            </function-decl>
>          </member-function>
>        </class-decl>
> -      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' id='type-id-460'>
> +      <enum-decl name='__anonymous_enum__1' is-anonymous='yes' is-declaration-only='yes' id='type-id-460'>
>          <underlying-type type-id='type-id-18'/>
>        </enum-decl>
>        <class-decl name='__anonymous_struct__23' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-220'>
> @@ -8864,7 +8864,7 @@
>        <class-decl name='__anonymous_struct__26' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-308'>
>
>            <member-type access='private'>
> -            <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-461'>
> +            <enum-decl name='__anonymous_enum__' is-anonymous='yes' is-declaration-only='yes' id='type-id-461'>
>                <underlying-type type-id='type-id-18'/>
>              </enum-decl>
>            </member-type>
> --
> 1.8.3.1
>
>
> --
>                 Dodji

Regards,
Giuliano.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 10/11] Add declaration-only enums to XML reader/writer.
  2020-07-07  8:31     ` Giuliano Procida
@ 2020-07-07 14:57       ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-07 14:57 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail, kernel-team

Giuliano Procida <gprocida@google.com> a écrit:

[...]

>> +  t->set_is_declaration_only(is_decl_only); // TODO: more to do here!
>
> I think this TODO was related to resolution and is dead.
> (Note to self: write better TODO text.)

Right.  Fixed, thanks.

I have updated the patch at
https://sourceware.org/git/?p=libabigail.git;a=commit;h=b53db3ad74844e20b163d7cfdfd7b980a3b13e86.
I am not attaching it here because it's quite big.  I have also rebased
it against recent master, so I had to update two more tests.  Please
find below its ChangeLog.

	* src/abg-reader.cc (build_enum_type_decl): Detect a
	declaration-only enum and flag it as such.
	(build_type_decl): Support reading the "is-declaration" attribute.
	(build_class_decl): Adjust.
	* src/abg-writer.cc (write_is_declaration_only): Renamed
	write_class_or_union_is_declaration_only into this.
	(write_enum_is_declaration_only): Remove.
	(write_type_decl, write_enum_type_decl)
	(write_class_decl_opening_tag, write_union_decl_opening_tag): Use
	write_is_declaration_only.
	* tests/data/test-read-dwarf/PR22122-libftdc.so.abi: Adjust.
	* tests/data/test-read-dwarf/test12-pr18844.so.abi: Likewise.
	* tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Likewise.

Signed-off-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>

[...]

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 06/11] Support incomplete enums in core and diff code.
       [not found]     ` <CAGvU0HkuOc74mfL9yLttK4Riwkrj9tmtc3VXxdHAsaCbn2153A@mail.gmail.com>
@ 2020-07-08  9:22       ` Dodji Seketeli
  2020-07-08 10:39         ` Giuliano Procida
  0 siblings, 1 reply; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-08  9:22 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail

Hello Giuliano,

Giuliano Procida <gprocida@google.com> a écrit:

> Hi Dodji.
>
> Overall this looks like an excellent compromise. In terms of the
> surgery on the type hierarchy, my main concerns would be that
>
> 1. things that are not class/union/enum but which fall under decl_base
> continue to get the same treatment

Agreed.

> 2. old places where class/union had declaration-only manipulation and
> new places where enums have the same both get the right down-casting

Yes.

> It looks like these are there. I have some further comments in-line,
> nothing significant.

Thanks.

[...]

>> +bool
>> +has_decl_only_def_change(const decl_base_sptr& first,
>> +                        const decl_base_sptr& second)
>> +{
>> +  if (!first || !second)
>> +    return false;
>> +
>> +  decl_base_sptr f =
>> +    look_through_decl_only(first);
>> +  decl_base_sptr s =
>> +    look_through_decl_only(second);
>> +
>> +  if (f->get_qualified_name() != s->get_qualified_name())
>> +    return false;
>> +
>> +  return (f->get_is_declaration_only() != s->get_is_declaration_only());
>
> This return statement doesn't need the outer ( ).

Fixed.

[...]

>>  /// Test if two @ref class_or_union_sptr are different just by the
>>  /// fact that one is decl-only and the other one is defined.
>>  ///
>> @@ -956,6 +1026,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
>>    return (f->get_is_declaration_only() != s->get_is_declaration_only());
>
> Same here on the return statement.

Fixed.

[...]

>> +bool
>> +has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
>> +                             const enum_type_decl_sptr& second)
>> +{
>> +  if (!first || !second)
>> +    return false;
>> +
>> +  enum_type_decl_sptr f = look_through_decl_only_enum(first);
>> +  enum_type_decl_sptr s = look_through_decl_only_enum(second);
>> +
>> +  if (f->get_qualified_name() != s->get_qualified_name())
>> +    return false;
>> +
>> +  return (f->get_is_declaration_only() != s->get_is_declaration_only());
>
> And again.

Fixed.

[...]

>> @@ -3423,7 +3427,9 @@ struct decl_base::priv
>>        is_artificial_(false),
>>        has_anonymous_parent_(false),
>>        context_(),
>> -      visibility_(VISIBILITY_DEFAULT)
>> +      visibility_(VISIBILITY_DEFAULT),
>> +      naked_definition_of_declaration_(),
>> +      is_declaration_only_()
>
> Would be clearer to say (false).

Fixed.

>>    {}
>>
>>    priv(interned_string name, const location& locus,
>> @@ -3434,7 +3440,9 @@ struct decl_base::priv
>>        name_(name),
>>        qualified_name_(name),
>>        linkage_name_(linkage_name),
>> -      visibility_(vis)
>> +      visibility_(vis),
>> +      naked_definition_of_declaration_(),
>> +      is_declaration_only_()
>
> Same here.

Fixed.

>>    {
>>      is_anonymous_ = name_.empty();
>>      has_anonymous_parent_ = false;
>> @@ -3446,7 +3454,9 @@ struct decl_base::priv
>>        has_anonymous_parent_(false),
>>        location_(l),
>>        context_(),
>> -      visibility_(VISIBILITY_DEFAULT)
>> +      visibility_(VISIBILITY_DEFAULT),
>> +      naked_definition_of_declaration_(),
>> +      is_declaration_only_()
>
> And again.

Fixed.

[...]

>> +/// Set a flag saying if the @ref enum_type_decl is a declaration-only
>> +/// @ref enum_type_decl.
>> +///
>> +/// @param f true if the @ref enum_type_decl is a decalaration-only
>
> Typo: decalaration / declaration.

Fixed.

[...]

>> +/// Test if a type is a enum. This function looks through typedefs.
>
> Typo: a enum / an enum.

Fixed.

[...]

>> +/// Test if a type is a enum. This function looks through typedefs.
>
> Same typo.

Fixed.

>> +///
>> +/// @parm t the type to consider.
>> +///
>> +/// @return the enum_decl if @p t is a enum_decl or null otherwise.
>
> Technically a typo: a enum_decl / an enum_decl.
> I'm not sure how it will render if you @ref the types.

Fixed.

>> +enum_type_decl_sptr
>> +is_compatible_with_enum_type(const decl_base_sptr& t)
>> +{return is_compatible_with_enum_type(is_type(t));}
>> +
>>  /// Test if a decl is an enum_type_decl
>>  ///
>>  /// @param d the decl to test for.
>> @@ -8270,24 +8386,19 @@ is_method_type(type_or_decl_base* t)
>>  /// @param the_klass the class (or union) to consider.
>
> Parameter is the_class.

Fixed.

>>  ///
>>  /// @return either the definition of the class, or the class itself.
>> +class_or_union*
>> +look_through_decl_only_class(class_or_union* the_class)
>> +{return is_class_or_union_type(look_through_decl_only(the_class));}
>> +
>> +/// If a class (or union) is a decl-only class, get its definition.
>> +/// Otherwise, just return the initial class.
>> +///
>> +/// @param the_klass the class (or union) to consider.
>
> Same here.

Fixed.

[...]


>> +decl_base_sptr
>> +look_through_decl_only(const decl_base& d)
>> +{
>> +  decl_base_sptr decl;
>> +  if (d.get_is_declaration_only())
>> +    decl = d.get_definition_of_declaration();
>> +
>> +  if (!decl)
>> +    return decl;
>> +
>> +  while (decl
>> +        && decl->get_is_declaration_only()
>> +        && decl->get_definition_of_declaration())
>> +    decl = decl->get_definition_of_declaration();
>> +
>> +  ABG_ASSERT(decl);
>> +  return decl;
>
> I had a suspicion that this code could be simplified a while ago.
>
> You should be able to simplify it to (something like):
>
> look_through_decl_only_class(class_or_union_sptr klass)
> {
>   if (!klass)
>     return klass;
>   while (klass->get_is_declaration_only()
>          && klass->get_definition_of_declaration())
>     klass = klass->get_definition_of_declaration();
>   return klass;
> }
>
> This is two things:
> 1. The function is simpler if it takes a (shared) pointer argument.
> You probably don't need the other overload.

Actually, I prefer keeping the function that takes reference.  It's
reused in the overload that takes a pointer.  Also, I have some
test/play programs on the side that use types instantiated on the stack
etc and that make use of these.  So they are useful in general, I think.

> 2. You don't need to retest decl on every loop or assert it at the
> end, just check once at the top as the loop condition preserves the
> invariant.

Yes, you are correct.  I have made this change in the updated patch.
Thanks.

[...]

[...]

>> +/// Look into a given corpus to find the enum type*s* that have a
>> +/// given qualified name.
>> +///
>> +/// @param qualified_name the qualified name of the type to look for.
>> +///
>> +/// @param corp the corpus to look into.
>> +///
>> +/// @return the vector of enum types that which name is @p qualified_name.
>
> Suggest: "that which name is" -> "named" (or "which have the name")
> (and again, below)

Of course.  Fixed.

[...]

Please find below an updated patch that is present in my updated
dodji/incomp-enum branch.

Thanks.


From 377b577cbbdc313e78b58631f5fb9bcc2c913a25 Mon Sep 17 00:00:00 2001
From: Giuliano Procida <gprocida@google.com>
Date: Wed, 10 Jun 2020 12:59:35 +0100
Subject: [PATCH 1/4] Support incomplete enums in core and diff code.

This is an initial implementation of the support for incomplete, also
known as forward-declared, enum types. I've not made any attempt to
refactor or share logic with the struct/union code.

	* include/abg-comp-filter.h (has_decl_only_def_change) : Declare
	New function.
	* src/abg-comp-filter.cc (there_is_a_decl_only_enum): Define new
	static function and ...
	(type_size_changed): ... use it here.
	(has_decl_only_def_change): Define new function and ...
	(categorize_harm{less, ful}_diff_node): ... use it here.
	* include/abg-fwd.h (enums_type, decl_base_wptr): Declare new
	typedefs.
	(look_through_decl_only_class): Declare new overload for
	class_or_union*.
	(is_compatible_with_enum_type, is_compatible_with_enum_type)
	(look_through_decl_only, lookup_enum_types, lookup_enum_types):
	Declare new functions.
	* include/abg-ir.h (decl_base::{get_is_declaration_only,
	set_is_declaration_only, set_definition_of_declaration,
	get_definition_of_declaration,
	get_naked_definition_of_declaration}): Declare new member
	functions.  They were moved here from the class_or_union class.
	(class_or_union::{get_earlier_declaration,
	set_earlier_declaration, get_definition_of_declaration,
	set_definition_of_declaration,
	get_naked_definition_of_declaration, get_is_declaration_only,
	set_is_declaration_only}): Remove these member functions.
	* src/abg-ir.cc (decl_base::priv::{declaration_,
	definition_of_declaration_, naked_definition_of_declaration_,
	is_declaration_only_}): Define data members.  Moved here from
	class_or_union.
	(decl_base::priv::priv): Adjust to initialize the new data
	members.
	(decl_base::{get_earlier_declaration, set_earlier_declaration,
	get_definition_of_declaration,
	get_naked_definition_of_declaration, get_is_declaration_only,
	set_is_declaration_only, set_definition_of_declaration}): Define
	member functions.
	(operator|): In the overload for (change_kind, change_kind),
	adjust the return type of the call to
	decl_base::get_definition_of_declaration.
	(look_through_decl_only): Define new function.
	(look_through_decl_only_class): Adjust.
	(look_through_decl_only_enum): Likewise.
	(maybe_update_types_lookup_map<class_decl>): Adjust return type of
	call to decl_base::get_definition_of_declaration.
	(types_defined_same_linux_kernel_corpus_public): Use
	look_through_decl_only_class rather than open coding it.
	(class_or_union::priv::{declaration_, definition_of_declaration_,
	naked_definition_of_declaration_, is_declaration_only_}): Remove
	these data members.  They are now carried by decl_base::priv.
	(class_or_union::{g,s}et_alignment_in_bits): Adjust.
	(class_or_union::{g,s}et_size_in_bits): Likewise.
	(class_or_union::operator==): Likewise.
	(equals): Adjust the overload for class_or_union.
	(is_compatible_with_enum_type)
	* src/abg-comparison.cc (try_to_diff<class_decl>): Adjust the
	return type of decl_base::get_definition_of_declaration.
	(leaf_diff_node_marker_visitor::visit_begin): Use
	filtering::has_decl_only_def_change rather than
	filtering::has_class_decl_only_def_change.  Decl-only changes to
	enums (or any other type really) will thus not be recorded as leaf
	changes.
	* src/abg-dwarf-reader.cc (get_scope_for_die): Adjust return type
	of decl_base::get_definition_of_declaration.
	* src/abg-default-reporter.cc (default_reporter::report): Report
	enum decl-only <-> definition changes.
	* src/abg-hash.cc (class_or_union::hash::operator()): In the
	overload for class_or_union& adjust the return type for
	decl_base::get_definition_of_declaration.

Signed-off-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-comp-filter.h   |  14 ++
 include/abg-fwd.h           |  36 ++++
 include/abg-ir.h            |  48 ++---
 src/abg-comp-filter.cc      | 133 ++++++++++++-
 src/abg-comparison.cc       |  10 +-
 src/abg-default-reporter.cc |  19 ++
 src/abg-dwarf-reader.cc     |   3 +-
 src/abg-hash.cc             |   3 +-
 src/abg-ir.cc               | 472 +++++++++++++++++++++++++++-----------------
 9 files changed, 519 insertions(+), 219 deletions(-)

diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h
index 8113003..556bad4 100644
--- a/include/abg-comp-filter.h
+++ b/include/abg-comp-filter.h
@@ -65,13 +65,27 @@ bool
 is_decl_only_class_with_size_change(const diff *diff);
 
 bool
+has_decl_only_def_change(const decl_base_sptr& first,
+			 const decl_base_sptr& second);
+
+bool
+has_decl_only_def_change(const diff *d);
+
+bool
 has_class_decl_only_def_change(const class_or_union_sptr& first,
 			       const class_or_union_sptr& second);
 
 bool
+has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
+			      const enum_type_decl_sptr& second);
+
+bool
 has_class_decl_only_def_change(const diff *diff);
 
 bool
+has_enum_decl_only_def_change(const diff *diff);
+
+bool
 has_basic_type_name_change(const diff *);
 
 bool
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index f23f4a4..bfd9f88 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -155,6 +155,12 @@ class enum_type_decl;
 /// Convenience typedef for shared pointer to a @ref enum_type_decl.
 typedef shared_ptr<enum_type_decl> enum_type_decl_sptr;
 
+/// Convenience typedef for a vector of @ref enum_type_decl_sptr
+typedef vector<enum_type_decl_sptr> enums_type;
+
+/// Convenience typedef for a weak pointer to a @ref decl_base.
+typedef weak_ptr<decl_base> decl_base_wptr;
+
 class class_or_union;
 
 typedef shared_ptr<class_or_union> class_or_union_sptr;
@@ -424,6 +430,12 @@ typedef_decl*
 is_typedef(type_base*);
 
 enum_type_decl_sptr
+is_compatible_with_enum_type(const type_base_sptr&);
+
+enum_type_decl_sptr
+is_compatible_with_enum_type(const decl_base_sptr&);
+
+enum_type_decl_sptr
 is_enum_type(const type_or_decl_base_sptr&);
 
 const enum_type_decl*
@@ -513,6 +525,24 @@ look_through_decl_only_class(const class_or_union&);
 class_or_union_sptr
 look_through_decl_only_class(class_or_union_sptr);
 
+class_or_union*
+look_through_decl_only_class(class_or_union*);
+
+enum_type_decl_sptr
+look_through_decl_only_enum(const enum_type_decl&);
+
+enum_type_decl_sptr
+look_through_decl_only_enum(enum_type_decl_sptr);
+
+decl_base_sptr
+look_through_decl_only(const decl_base&);
+
+decl_base*
+look_through_decl_only(decl_base*);
+
+decl_base_sptr
+look_through_decl_only(const decl_base_sptr&);
+
 var_decl*
 is_var_decl(const type_or_decl_base*);
 
@@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&);
 enum_type_decl_sptr
 lookup_enum_type(const interned_string&, const corpus&);
 
+const type_base_wptrs_type*
+lookup_enum_types(const interned_string&, const corpus&);
+
+const type_base_wptrs_type*
+lookup_enum_types(const string&, const corpus&);
+
 enum_type_decl_sptr
 lookup_enum_type_per_location(const interned_string&, const corpus&);
 
diff --git a/include/abg-ir.h b/include/abg-ir.h
index c2b66c4..5b13dc9 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -1553,6 +1553,27 @@ public:
   void
   set_visibility(visibility v);
 
+  const decl_base_sptr
+  get_earlier_declaration() const;
+
+  void
+  set_earlier_declaration(const decl_base_sptr&);
+
+  const decl_base_sptr
+  get_definition_of_declaration() const;
+
+  void
+  set_definition_of_declaration(const decl_base_sptr&);
+
+  const decl_base*
+  get_naked_definition_of_declaration() const;
+
+  bool
+  get_is_declaration_only() const;
+
+  void
+  set_is_declaration_only(bool f);
+
   friend type_base_sptr
   canonicalize(type_base_sptr);
 
@@ -3776,27 +3797,6 @@ public:
   void
   set_naming_typedef(const typedef_decl_sptr&);
 
-  bool
-  get_is_declaration_only() const;
-
-  void
-  set_is_declaration_only(bool f);
-
-  void
-  set_definition_of_declaration(class_or_union_sptr);
-
-  const class_or_union_sptr
-  get_definition_of_declaration() const;
-
-  const class_or_union*
-  get_naked_definition_of_declaration() const;
-
-  decl_base_sptr
-  get_earlier_declaration() const;
-
-  void
-  set_earlier_declaration(decl_base_sptr declaration);
-
  void
   insert_member_type(type_base_sptr t,
 		     declarations::iterator before);
@@ -4020,12 +4020,6 @@ public:
   class_decl(const environment* env, const string& name, bool is_struct,
 	     bool is_declaration_only = true);
 
-  const class_decl_sptr
-  get_definition_of_declaration() const;
-
-  const class_decl*
-  get_naked_definition_of_declaration() const;
-
   virtual string
   get_pretty_representation(bool internal = false,
 			    bool qualified_name = true) const;
diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
index 702d223..0b0fbe4 100644
--- a/src/abg-comp-filter.cc
+++ b/src/abg-comp-filter.cc
@@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1,
   return false;
 }
 
+/// Test if there is a enum that is declaration-only among the two
+/// enums in parameter.
+///
+/// @param enum1 the first enum to consider.
+///
+/// @param enum2 the second enum to consider.
+///
+/// @return true if either enums are declaration-only, false
+/// otherwise.
+static bool
+there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1,
+			  const enum_type_decl_sptr& enum2)
+{
+  if ((enum1 && enum1->get_is_declaration_only())
+      || (enum2 && enum2->get_is_declaration_only()))
+    return true;
+  return false;
+}
+
 /// Test if the diff involves a declaration-only class.
 ///
 /// @param diff the class diff to consider.
@@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s)
       || f->get_size_in_bits() == 0
       || s->get_size_in_bits() == 0
       || there_is_a_decl_only_class(is_compatible_with_class_type(f),
-				    is_compatible_with_class_type(s)))
+				    is_compatible_with_class_type(s))
+      || there_is_a_decl_only_enum(is_compatible_with_enum_type(f),
+				   is_compatible_with_enum_type(s)))
     return false;
 
   return f->get_size_in_bits() != s->get_size_in_bits();
@@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_union_sptr& first,
   if (!first || !second)
     return false;
 
-  class_or_union_sptr f =
-    look_through_decl_only_class(first);
-  class_or_union_sptr s =
-    look_through_decl_only_class(second);
+  class_or_union_sptr f = look_through_decl_only_class(first);
+  class_or_union_sptr s = look_through_decl_only_class(second);
 
   return is_decl_only_class_with_size_change(*f, *s);
 }
@@ -929,6 +948,57 @@ is_decl_only_class_with_size_change(const diff *diff)
   return is_decl_only_class_with_size_change(f, s);
 }
 
+/// Test if two @ref decl_base_sptr are different just by the
+/// fact that one is decl-only and the other one is defined.
+///
+/// @param first the first decl to consider.
+///
+/// @param second the second decl to consider.
+///
+/// @return true iff the two arguments are different just by the fact
+/// that one is decl-only and the other one is defined.
+bool
+has_decl_only_def_change(const decl_base_sptr& first,
+			 const decl_base_sptr& second)
+{
+  if (!first || !second)
+    return false;
+
+  decl_base_sptr f =
+    look_through_decl_only(first);
+  decl_base_sptr s =
+    look_through_decl_only(second);
+
+  if (f->get_qualified_name() != s->get_qualified_name())
+    return false;
+
+  return f->get_is_declaration_only() != s->get_is_declaration_only();
+}
+
+/// Test if a diff carries a change in which the two decls are
+/// different by the fact that one is a decl-only and the other one is
+/// defined.
+///
+/// @param diff the diff node to consider.
+///
+/// @return true if the diff carries a change in which the two decls
+/// are different by the fact that one is a decl-only and the other
+/// one is defined.
+bool
+has_decl_only_def_change(const diff *d)
+{
+  if (!d)
+    return false;
+
+  decl_base_sptr f =
+    look_through_decl_only(is_decl(d->first_subject()));
+  decl_base_sptr s =
+    look_through_decl_only(is_decl(d->second_subject()));
+
+  return has_decl_only_def_change(f, s);
+}
+
+
 /// Test if two @ref class_or_union_sptr are different just by the
 /// fact that one is decl-only and the other one is defined.
 ///
@@ -953,7 +1023,32 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
   if (f->get_qualified_name() != s->get_qualified_name())
     return false;
 
-  return (f->get_is_declaration_only() != s->get_is_declaration_only());
+  return f->get_is_declaration_only() != s->get_is_declaration_only();
+}
+
+/// Test if two @ref enum_sptr are different just by the
+/// fact that one is decl-only and the other one is defined.
+///
+/// @param first the first enum to consider.
+///
+/// @param second the second enum to consider.
+///
+/// @return true iff the two arguments are different just by the fact
+/// that one is decl-only and the other one is defined.
+bool
+has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
+			      const enum_type_decl_sptr& second)
+{
+  if (!first || !second)
+    return false;
+
+  enum_type_decl_sptr f = look_through_decl_only_enum(first);
+  enum_type_decl_sptr s = look_through_decl_only_enum(second);
+
+  if (f->get_qualified_name() != s->get_qualified_name())
+    return false;
+
+  return f->get_is_declaration_only() != s->get_is_declaration_only();
 }
 
 /// Test if a class_or_union_diff carries a change in which the two
@@ -980,6 +1075,28 @@ has_class_decl_only_def_change(const diff *diff)
   return has_class_decl_only_def_change(f, s);
 }
 
+/// Test if a enum_diff carries a change in which the two enums are
+/// different by the fact that one is a decl-only and the other one is
+/// defined.
+///
+/// @param diff the diff node to consider.
+///
+/// @return true if the enum_diff carries a change in which the two
+/// enums are different by the fact that one is a decl-only and the
+/// other one is defined.
+bool
+has_enum_decl_only_def_change(const diff *diff)
+{
+  const enum_diff *d = dynamic_cast<const enum_diff*>(diff);
+  if (!d)
+    return false;
+
+  enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum());
+  enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum());
+
+  return has_enum_decl_only_def_change(f, s);
+}
+
 /// Test if a diff node carries a basic type name change.
 ///
 /// @param d the diff node to consider.
@@ -1517,7 +1634,8 @@ categorize_harmless_diff_node(diff *d, bool pre)
       decl_base_sptr f = is_decl(d->first_subject()),
 	s = is_decl(d->second_subject());
 
-      if (has_class_decl_only_def_change(d))
+      if (has_class_decl_only_def_change(d)
+	  || has_enum_decl_only_def_change(d))
 	category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY;
 
       if (access_changed(f, s))
@@ -1608,6 +1726,7 @@ categorize_harmful_diff_node(diff *d, bool pre)
       //
       // TODO: be more specific -- not all size changes are harmful.
       if (!has_class_decl_only_def_change(d)
+	  && !has_enum_decl_only_def_change(d)
 	  && (type_size_changed(f, s)
 	      || data_member_offset_changed(f, s)
 	      || non_static_data_member_type_size_changed(f, s)
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index d0f1d21..b6f065f 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -2827,13 +2827,15 @@ try_to_diff<class_decl>(const type_or_decl_base_sptr first,
 
       if (f->get_is_declaration_only())
 	{
-	  class_decl_sptr f2 = f->get_definition_of_declaration();
+	  class_decl_sptr f2 =
+	    is_class_type (f->get_definition_of_declaration());
 	  if (f2)
 	    f = f2;
 	}
       if (s->get_is_declaration_only())
 	{
-	  class_decl_sptr s2 = s->get_definition_of_declaration();
+	  class_decl_sptr s2 =
+	    is_class_type(s->get_definition_of_declaration());
 	  if (s2)
 	    s = s2;
 	}
@@ -10953,8 +10955,8 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor
 	// typedef change which underlying type is an anonymous
 	// struct/union.
 	&& !is_anonymous_class_or_union_diff(d)
-	// Don't show decl-only-ness changes of classes either.
-	&& !filtering::has_class_decl_only_def_change(d)
+	// Don't show decl-only-ness changes either.
+	&& !filtering::has_decl_only_def_change(d)
 	// Sometime, we can encounter artifacts of bogus DWARF that
 	// yield a diff node for a decl-only class (and empty class
 	// with the is_declaration flag set) that carries a non-zero
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 2acb695..cbf8c2b 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out,
   enum_type_decl_sptr first = d.first_enum(), second = d.second_enum();
 
   const diff_context_sptr& ctxt = d.context();
+
+  // Report enum decl-only <-> definition changes.
+  if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
+    if (filtering::has_enum_decl_only_def_change(first, second))
+      {
+	string was =
+	  first->get_is_declaration_only()
+	  ? " was a declaration-only enum type"
+	  : " was a defined enum type";
+
+	string is_now =
+	  second->get_is_declaration_only()
+	  ? " and is now a declaration-only enum type"
+	  : " and is now a defined enum type";
+
+	out << indent << "enum type " << name << was << is_now << "\n";
+	return;
+      }
+
   report_name_size_and_alignment_changes(first, second, ctxt,
 					 out, indent);
   maybe_report_diff_for_member(first, second, ctxt, out, indent);
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index ba4e750..db43aa7 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -12315,7 +12315,8 @@ get_scope_for_die(read_context& ctxt,
   class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d);
   if (cl && cl->get_is_declaration_only())
     {
-      scope_decl_sptr scop (cl->get_definition_of_declaration());
+      scope_decl_sptr scop  =
+	dynamic_pointer_cast<scope_decl>(cl->get_definition_of_declaration());
       if (scop)
 	s = scop;
       else
diff --git a/src/abg-hash.cc b/src/abg-hash.cc
index c1cdc57..5d2861f 100644
--- a/src/abg-hash.cc
+++ b/src/abg-hash.cc
@@ -635,7 +635,8 @@ class_or_union::hash::operator()(const class_or_union& t) const
   if (t.get_is_declaration_only())
     {
       ABG_ASSERT(t.get_definition_of_declaration());
-      size_t v = operator()(*t.get_definition_of_declaration());
+      size_t v = operator()
+	(*is_class_or_union_type(t.get_definition_of_declaration()));
       return v;
     }
 
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index a434ec6..15bf124 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -3416,6 +3416,10 @@ struct decl_base::priv
     interned_string	scoped_name_;
   interned_string	linkage_name_;
   visibility		visibility_;
+  decl_base_sptr	declaration_;
+  decl_base_wptr	definition_of_declaration_;
+  decl_base*		naked_definition_of_declaration_;
+  bool			is_declaration_only_;
 
   priv()
     : in_pub_sym_tab_(false),
@@ -3423,7 +3427,9 @@ struct decl_base::priv
       is_artificial_(false),
       has_anonymous_parent_(false),
       context_(),
-      visibility_(VISIBILITY_DEFAULT)
+      visibility_(VISIBILITY_DEFAULT),
+      naked_definition_of_declaration_(),
+      is_declaration_only_(false)
   {}
 
   priv(interned_string name, const location& locus,
@@ -3434,7 +3440,9 @@ struct decl_base::priv
       name_(name),
       qualified_name_(name),
       linkage_name_(linkage_name),
-      visibility_(vis)
+      visibility_(vis),
+      naked_definition_of_declaration_(),
+      is_declaration_only_(false)
   {
     is_anonymous_ = name_.empty();
     has_anonymous_parent_ = false;
@@ -3446,7 +3454,9 @@ struct decl_base::priv
       has_anonymous_parent_(false),
       location_(l),
       context_(),
-      visibility_(VISIBILITY_DEFAULT)
+      visibility_(VISIBILITY_DEFAULT),
+      naked_definition_of_declaration_(),
+      is_declaration_only_(false)
   {}
 
   ~priv()
@@ -3881,6 +3891,80 @@ const interned_string&
 decl_base::get_scoped_name() const
 {return priv_->scoped_name_;}
 
+/// If this @ref decl_base is a definition, get its earlier
+/// declaration.
+///
+/// @return the earlier declaration of the class, if any.
+const decl_base_sptr
+decl_base::get_earlier_declaration() const
+{return priv_->declaration_;}
+
+/// set the earlier declaration of this @ref decl_base definition.
+///
+/// @param d the earlier declaration to set.  Note that it's set only
+/// if it's a pure declaration.
+void
+decl_base::set_earlier_declaration(const decl_base_sptr& d)
+{
+  if (d && d->get_is_declaration_only())
+    priv_->declaration_ = d;
+}
+
+
+/// If this @ref decl_base is declaration-only, get its definition, if
+/// any.
+///
+/// @return the definition of this decl-only @ref decl_base.
+const decl_base_sptr
+decl_base::get_definition_of_declaration() const
+{return priv_->definition_of_declaration_.lock();}
+
+///  If this @ref decl_base is declaration-only, get its definition,
+///  if any.
+///
+/// Note that this function doesn't return a smart pointer, but rather
+/// the underlying pointer managed by the smart pointer.  So it's as
+/// fast as possible.  This getter is to be used in code paths that
+/// are proven to be performance hot spots; especially, when comparing
+/// sensitive types like enums, classes or unions.  Those are compared
+/// extremely frequently and thus, their access to the definition of
+/// declaration must be fast.
+///
+/// @return the definition of the declaration.
+const decl_base*
+decl_base::get_naked_definition_of_declaration() const
+{return priv_->naked_definition_of_declaration_;}
+
+/// Test if a @ref decl_base is a declaration-only decl.
+///
+/// @return true iff the current @ref decl_base is declaration-only.
+bool
+decl_base::get_is_declaration_only() const
+{return priv_->is_declaration_only_;}
+
+/// Set a flag saying if the @ref enum_type_decl is a declaration-only
+/// @ref enum_type_decl.
+///
+/// @param f true if the @ref enum_type_decl is a declaration-only
+/// @ref enum_type_decl.
+void
+decl_base::set_is_declaration_only(bool f)
+{
+  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
+
+  priv_->is_declaration_only_ = f;
+
+  if (update_types_lookup_map)
+    if (scope_decl* s = get_scope())
+      {
+	scope_decl::declarations::iterator i;
+	if (s->find_iterator_for_member(this, i))
+	  maybe_update_types_lookup_map(*i);
+	else
+	  ABG_ASSERT_NOT_REACHED;
+      }
+}
+
 change_kind
 operator|(change_kind l, change_kind r)
 {
@@ -4236,7 +4320,7 @@ operator!=(const type_base_sptr& l, const type_base_sptr& r)
 
 /// Tests if a declaration has got a scope.
 ///
-/// @param d the decalaration to consider.
+/// @param d the declaration to consider.
 ///
 /// @return true if the declaration has got a scope, false otherwise.
 bool
@@ -4245,7 +4329,7 @@ has_scope(const decl_base& d)
 
 /// Tests if a declaration has got a scope.
 ///
-/// @param d the decalaration to consider.
+/// @param d the declaration to consider.
 ///
 /// @return true if the declaration has got a scope, false otherwise.
 bool
@@ -6686,7 +6770,7 @@ get_location(const decl_base_sptr& decl)
       if (class_or_union_sptr c = is_class_or_union_type(decl))
 	if (c->get_is_declaration_only() && c->get_definition_of_declaration())
 	  {
-	    c = c->get_definition_of_declaration();
+	    c = is_class_or_union_type(c->get_definition_of_declaration());
 	    loc = c->get_location();
 	  }
     }
@@ -7925,6 +8009,40 @@ typedef_decl*
 is_typedef(type_base* t)
 {return dynamic_cast<typedef_decl*>(t);}
 
+/// Test if a type is an enum. This function looks through typedefs.
+///
+/// @parm t the type to consider.
+///
+/// @return the enum_decl if @p t is an @ref enum_decl or null
+/// otherwise.
+enum_type_decl_sptr
+is_compatible_with_enum_type(const type_base_sptr& t)
+{
+  if (!t)
+    return enum_type_decl_sptr();
+
+  // Normally we should strip typedefs entirely, but this is
+  // potentially costly, especially on binaries with huge changesets
+  // like the Linux Kernel.  So we just get the leaf types for now.
+  //
+  // Maybe there should be an option by which users accepts to pay the
+  // CPU usage toll in exchange for finer filtering?
+
+  // type_base_sptr ty = strip_typedef(t);
+  type_base_sptr ty = peel_typedef_type(t);;
+  return is_enum_type(ty);
+}
+
+/// Test if a type is an enum. This function looks through typedefs.
+///
+/// @parm t the type to consider.
+///
+/// @return the enum_decl if @p t is an @ref enum_decl or null
+/// otherwise.
+enum_type_decl_sptr
+is_compatible_with_enum_type(const decl_base_sptr& t)
+{return is_compatible_with_enum_type(is_type(t));}
+
 /// Test if a decl is an enum_type_decl
 ///
 /// @param d the decl to test for.
@@ -8267,27 +8385,22 @@ is_method_type(type_or_decl_base* t)
 /// If a class (or union) is a decl-only class, get its definition.
 /// Otherwise, just return the initial class.
 ///
-/// @param the_klass the class (or union) to consider.
+/// @param the_class the class (or union) to consider.
+///
+/// @return either the definition of the class, or the class itself.
+class_or_union*
+look_through_decl_only_class(class_or_union* the_class)
+{return is_class_or_union_type(look_through_decl_only(the_class));}
+
+/// If a class (or union) is a decl-only class, get its definition.
+/// Otherwise, just return the initial class.
+///
+/// @param the_class the class (or union) to consider.
 ///
 /// @return either the definition of the class, or the class itself.
 class_or_union_sptr
 look_through_decl_only_class(const class_or_union& the_class)
-{
-  class_or_union_sptr klass;
-  if (the_class.get_is_declaration_only())
-    klass = the_class.get_definition_of_declaration();
-
-  if (!klass)
-    return klass;
-
-  while (klass
-	 && klass->get_is_declaration_only()
-	 && klass->get_definition_of_declaration())
-    klass = klass->get_definition_of_declaration();
-
-  ABG_ASSERT(klass);
-  return klass;
-}
+{return is_class_or_union_type(look_through_decl_only(the_class));}
 
 /// If a class (or union) is a decl-only class, get its definition.
 /// Otherwise, just return the initial class.
@@ -8297,13 +8410,84 @@ look_through_decl_only_class(const class_or_union& the_class)
 /// @return either the definition of the class, or the class itself.
 class_or_union_sptr
 look_through_decl_only_class(class_or_union_sptr klass)
+{return is_class_or_union_type(look_through_decl_only(klass));}
+
+/// If an enum is a decl-only enum, get its definition.
+/// Otherwise, just return the initial enum.
+///
+/// @param the_enum the enum to consider.
+///
+/// @return either the definition of the enum, or the enum itself.
+enum_type_decl_sptr
+look_through_decl_only_enum(const enum_type_decl& the_enum)
+{return is_enum_type(look_through_decl_only(the_enum));}
+
+/// If an enum is a decl-only enum, get its definition.
+/// Otherwise, just return the initial enum.
+///
+/// @param enom the enum to consider.
+///
+/// @return either the definition of the enum, or the enum itself.
+enum_type_decl_sptr
+look_through_decl_only_enum(enum_type_decl_sptr enom)
+{return is_enum_type(look_through_decl_only(enom));}
+
+/// If a decl is decl-only get its definition.  Otherwise, just return nil.
+///
+/// @param d the decl to consider.
+///
+/// @return either the definition of the decl, or nil.
+decl_base_sptr
+look_through_decl_only(const decl_base& d)
+{
+  decl_base_sptr decl;
+  if (d.get_is_declaration_only())
+    decl = d.get_definition_of_declaration();
+
+  if (!decl)
+    return decl;
+
+  while (decl->get_is_declaration_only()
+	 && decl->get_definition_of_declaration())
+    decl = decl->get_definition_of_declaration();
+
+  ABG_ASSERT(decl);
+  return decl;
+}
+
+/// If a decl is decl-only enum, get its definition.  Otherwise, just
+/// return the initial decl.
+///
+/// @param d the decl to consider.
+///
+/// @return either the definition of the enum, or the decl itself.
+decl_base*
+look_through_decl_only(decl_base* d)
+{
+  if (!d)
+    return d;
+
+  decl_base* result = look_through_decl_only(*d).get();
+  if (!result)
+    result = d;
+
+  return result;
+}
+
+/// If a decl is decl-only get its definition.  Otherwise, just return nil.
+///
+/// @param d the decl to consider.
+///
+/// @return either the definition of the decl, or nil.
+decl_base_sptr
+look_through_decl_only(const decl_base_sptr& d)
 {
-  if (!klass)
-    return klass;
+  if (!d)
+    return d;
 
-  class_or_union_sptr result = look_through_decl_only_class(*klass);
+  decl_base_sptr result = look_through_decl_only(*d);
   if (!result)
-    result = klass;
+    result = d;
 
   return result;
 }
@@ -8784,7 +8968,7 @@ lookup_union_type_per_location(const string& loc, const corpus& corp)
   return lookup_union_type_per_location(env->intern(loc), corp);
 }
 
-/// Lookup a enum type from a translation unit.
+/// Lookup an enum type from a translation unit.
 ///
 /// This is done by looking the type up in the type map that is
 /// maintained in the translation unit.  So this is as fast as
@@ -8802,7 +8986,7 @@ lookup_enum_type(const interned_string& type_name, const translation_unit& tu)
 					    tu.get_types().enum_types());
 }
 
-/// Lookup a enum type from a translation unit.
+/// Lookup an enum type from a translation unit.
 ///
 /// This is done by looking the type up in the type map that is
 /// maintained in the translation unit.  So this is as fast as
@@ -10004,7 +10188,7 @@ lookup_class_type(const interned_string& qualified_name, const corpus& corp)
 ///
 /// @param corp the corpus to look into.
 ///
-/// @return the vector of class types that which name is @p qualified_name.
+/// @return the vector of class types named @p qualified_name.
 const type_base_wptrs_type *
 lookup_class_types(const interned_string& qualified_name, const corpus& corp)
 {
@@ -10103,7 +10287,7 @@ lookup_union_type(const string& type_name, const corpus& corp)
   return lookup_union_type(s, corp);
 }
 
-/// Look into a given corpus to find a enum type which has the same
+/// Look into a given corpus to find an enum type which has the same
 /// qualified name as a given enum type.
 ///
 /// If the per-corpus type map is non-empty (because the corpus allows
@@ -10166,6 +10350,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp)
   return result;
 }
 
+/// Look into a given corpus to find the enum type*s* that have a
+/// given qualified name.
+///
+/// @param qualified_name the qualified name of the type to look for.
+///
+/// @param corp the corpus to look into.
+///
+/// @return the vector of enum types that which name is @p qualified_name.
+const type_base_wptrs_type *
+lookup_enum_types(const interned_string& qualified_name, const corpus& corp)
+{
+  const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types();
+
+  return lookup_types_in_map(qualified_name, m);
+}
+
+/// Look into a given corpus to find the enum type*s* that have a
+/// given qualified name.
+///
+/// @param qualified_name the qualified name of the type to look for.
+///
+/// @param corp the corpus to look into.
+///
+/// @return the vector of enum types that which name is @p qualified_name.
+const type_base_wptrs_type*
+lookup_enum_types(const string& qualified_name, const corpus& corp)
+{
+  interned_string s = corp.get_environment()->intern(qualified_name);
+  return lookup_enum_types(s, corp);
+}
+
 /// Look up an @ref enum_type_decl from a given corpus, by its location.
 ///
 /// @param loc the location to consider.
@@ -10767,7 +10982,8 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type,
   bool update_qname_map = true;
   if (type->get_is_declaration_only())
     {
-      if (class_decl_sptr def = class_type->get_definition_of_declaration())
+      if (class_decl_sptr def =
+	  is_class_type(class_type->get_definition_of_declaration()))
 	type = def;
       else
 	update_qname_map = false;
@@ -11683,10 +11899,8 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
 
   // Look through declaration-only types.  That is, get the associated
   // definition type.
-  if (c1 && c1->get_is_declaration_only())
-    c1 = c1->get_definition_of_declaration().get();
-  if (c2 && c2->get_is_declaration_only())
-    c2 = c2->get_definition_of_declaration().get();
+  c1 = look_through_decl_only_class(c1);
+  c2 = look_through_decl_only_class(c2);
 
   if (c1 && c2)
     {
@@ -12079,6 +12293,23 @@ canonicalize(type_base_sptr t)
   return canonical;
 }
 
+
+/// Set the definition of this declaration-only @ref decl_base.
+///
+/// @param d the new definition to set.
+void
+decl_base::set_definition_of_declaration(const decl_base_sptr& d)
+{
+  ABG_ASSERT(get_is_declaration_only());
+  priv_->definition_of_declaration_ = d;
+  priv_->definition_of_declaration_ = d;
+  if (type_base *t = is_type(this))
+    if (type_base_sptr canonical_type = is_type(d)->get_canonical_type())
+      t->priv_->canonical_type = canonical_type;
+
+  priv_->naked_definition_of_declaration_ = const_cast<decl_base*>(d.get());
+}
+
 /// The constructor of @ref type_base.
 ///
 /// @param s the size of the type, in bits.
@@ -14978,7 +15209,6 @@ class enum_type_decl::priv
   priv();
 
 public:
-
   priv(type_base_sptr underlying_type,
        enumerators& enumerators)
     : underlying_type_(underlying_type),
@@ -17987,9 +18217,6 @@ function_decl::parameter::get_pretty_representation(bool internal,
 struct class_or_union::priv
 {
   typedef_decl_wptr		naming_typedef_;
-  decl_base_sptr		declaration_;
-  class_or_union_wptr		definition_of_declaration_;
-  class_or_union*		naked_definition_of_declaration_;
   member_types			member_types_;
   data_members			data_members_;
   data_members			non_static_data_members_;
@@ -18001,21 +18228,16 @@ struct class_or_union::priv
   string_mem_fn_ptr_map_type	signature_2_mem_fn_map_;
   member_function_templates	member_function_templates_;
   member_class_templates	member_class_templates_;
-  bool				is_declaration_only_;
 
   priv()
-    : naked_definition_of_declaration_(),
-      is_declaration_only_(false)
   {}
 
   priv(class_or_union::member_types& mbr_types,
        class_or_union::data_members& data_mbrs,
        class_or_union::member_functions& mbr_fns)
-    : naked_definition_of_declaration_(),
-      member_types_(mbr_types),
+    : member_types_(mbr_types),
       data_members_(data_mbrs),
-      member_functions_(mbr_fns),
-      is_declaration_only_(false)
+      member_functions_(mbr_fns)
   {
     for (data_members::const_iterator i = data_members_.begin();
 	 i != data_members_.end();
@@ -18024,11 +18246,6 @@ struct class_or_union::priv
 	non_static_data_members_.push_back(*i);
   }
 
-  priv(bool is_declaration_only)
-    : naked_definition_of_declaration_(),
-      is_declaration_only_(is_declaration_only)
-  {}
-
   /// Mark a class or union or union as being currently compared using
   /// the class_or_union== operator.
   ///
@@ -18244,8 +18461,10 @@ class_or_union::class_or_union(const environment* env, const string& name,
     decl_base(env, name, location(), name),
     type_base(env, 0, 0),
     scope_type_decl(env, name, 0, 0, location()),
-    priv_(new priv(is_declaration_only))
-{}
+    priv_(new priv)
+{
+  set_is_declaration_only(is_declaration_only);
+}
 
 /// This implements the ir_traversable_base::traverse pure virtual
 /// function.
@@ -18465,7 +18684,8 @@ size_t
 class_or_union::get_alignment_in_bits() const
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    return get_definition_of_declaration()->get_alignment_in_bits();
+    return is_class_or_union_type
+      (get_definition_of_declaration())->get_alignment_in_bits();
 
    return type_base::get_alignment_in_bits();
 }
@@ -18480,7 +18700,8 @@ void
 class_or_union::set_alignment_in_bits(size_t a)
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    get_definition_of_declaration()->set_alignment_in_bits(a);
+    is_class_or_union_type
+      (get_definition_of_declaration()) ->set_alignment_in_bits(a);
   else
     type_base::set_alignment_in_bits(a);
 }
@@ -18495,7 +18716,8 @@ void
 class_or_union::set_size_in_bits(size_t s)
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    get_definition_of_declaration()->set_size_in_bits(s);
+    is_class_or_union_type
+      (get_definition_of_declaration())->set_size_in_bits(s);
   else
     type_base::set_size_in_bits(s);
 }
@@ -18510,42 +18732,12 @@ size_t
 class_or_union::get_size_in_bits() const
 {
   if (get_is_declaration_only() && get_definition_of_declaration())
-    return get_definition_of_declaration()->get_size_in_bits();
+    return is_class_or_union_type
+      (get_definition_of_declaration())->get_size_in_bits();
 
   return type_base::get_size_in_bits();
 }
 
-/// Test if a @ref class_or_union is a declaration-only @ref
-/// class_or_union.
-///
-/// @return true iff the current @ref class_or_union is a
-/// declaration-only @ref class_or_union.
-bool
-class_or_union::get_is_declaration_only() const
-{return priv_->is_declaration_only_;}
-
-/// Set a flag saying if the @ref class_or_union is a declaration-only
-/// @ref class_or_union.
-///
-/// @param f true if the @ref class_or_union is a decalaration-only
-/// @ref class_or_union.
-void
-class_or_union::set_is_declaration_only(bool f)
-{
-  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
-
-  priv_->is_declaration_only_ = f;
-
-  if (update_types_lookup_map)
-    if (scope_decl* s = get_scope())
-      {
-	declarations::iterator i;
-	if (s->find_iterator_for_member(this, i))
-	  maybe_update_types_lookup_map(*i);
-	else
-	  ABG_ASSERT_NOT_REACHED;
-      }
-}
 
 /// Getter for the naming typedef of the current class.
 ///
@@ -18577,64 +18769,6 @@ class_or_union::set_naming_typedef(const typedef_decl_sptr& typedef_type)
   priv_->naming_typedef_ = typedef_type;
 }
 
-/// Set the definition of this declaration-only @ref class_or_union.
-///
-/// @param d the new definition to set.
-void
-class_or_union::set_definition_of_declaration(class_or_union_sptr d)
-{
-  ABG_ASSERT(get_is_declaration_only());
-  priv_->definition_of_declaration_ = d;
-  if (d->get_canonical_type())
-    type_base::priv_->canonical_type = d->get_canonical_type();
-
-  priv_->naked_definition_of_declaration_ = d.get();
-}
-
-/// If this @ref class_or_union_sptr is declaration-only, get its
-/// definition, if any.
-///
-/// @return the definition of this decl-only class.
-const class_or_union_sptr
-class_or_union::get_definition_of_declaration() const
-{return priv_->definition_of_declaration_.lock();}
-
-///  If this @ref class_or_union is declaration-only, get its
-///  definition, if any.
-///
-/// Note that this function doesn't return a smart pointer, but rather
-/// the underlying pointer managed by the smart pointer.  So it's as
-/// fast as possible.  This getter is to be used in code paths that
-/// are proven to be performance hot spots; especially, when comparing
-/// sensitive types like class or unions.  Those are compared
-/// extremely frequently and thus, their access to the definition of
-/// declaration must be fast.
-///
-/// @return the definition of the class.
-const class_or_union*
-class_or_union::get_naked_definition_of_declaration() const
-{return priv_->naked_definition_of_declaration_;}
-
-/// If this @ref class_or_union_sptr is a definitin, get its earlier
-/// declaration.
-///
-/// @return the earlier declaration of the class, if any.
-decl_base_sptr
-class_or_union::get_earlier_declaration() const
-{return priv_->declaration_;}
-
-/// set the earlier declaration of this @ref class_or_union definition.
-///
-/// @param declaration the earlier declaration to set.  Note that it's
-/// set only if it's a pure declaration.
-void
-class_or_union::set_earlier_declaration(decl_base_sptr declaration)
-{
-  class_or_union_sptr cl = dynamic_pointer_cast<class_or_union>(declaration);
-  if (cl && cl->get_is_declaration_only())
-    priv_->declaration_ = declaration;
-}
-
 /// Get the member types of this @ref class_or_union.
 ///
 /// @return a vector of the member types of this ref class_or_union.
@@ -19082,15 +19216,16 @@ class_or_union::operator==(const decl_base& other) const
   if (!canonical_type
       && get_is_declaration_only()
       && get_naked_definition_of_declaration())
-    canonical_type =
-      get_naked_definition_of_declaration()->get_naked_canonical_type();
+    canonical_type = is_class_or_union_type
+      (get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   // Likewise for the other class.
   if (!other_canonical_type
       && op->get_is_declaration_only()
       && op->get_naked_definition_of_declaration())
     other_canonical_type =
-      op->get_naked_definition_of_declaration()->get_naked_canonical_type();
+      is_class_or_union_type
+      (op->get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   if (canonical_type && other_canonical_type)
     return canonical_type == other_canonical_type;
@@ -19161,11 +19296,11 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
   if (l_is_decl_only || r_is_decl_only)
     {
       const class_or_union* def1 = l_is_decl_only
-	? l.get_naked_definition_of_declaration()
+	? is_class_or_union_type(l.get_naked_definition_of_declaration())
 	: &l;
 
       const class_or_union* def2 = r_is_decl_only
-	? r.get_naked_definition_of_declaration()
+	? is_class_or_union_type(r.get_naked_definition_of_declaration())
 	: &r;
 
       if (!def1 || !def2)
@@ -19784,30 +19919,6 @@ class_decl::on_canonical_type_set()
     sort_virtual_member_functions(i->second);
 }
 
-///  If this @ref class_decl is declaration-only, get its definition,
-///  if any.
-///
-/// @return the definition of the class.
-const class_decl_sptr
-class_decl::get_definition_of_declaration() const
-{return is_class_type(class_or_union::get_definition_of_declaration());}
-
-///  If this @ref class_decl is declaration-only, get its definition,
-///  if any.
-///
-/// Note that this function doesn't return a smart pointer, but rather
-/// the underlying pointer managed by the smart pointer.  So it's as
-/// fast as possible.  This getter is to be used in code paths that
-/// are proven to be performance hot spots; especially, when comparing
-/// sensitive types like class or unions.  Those are compared
-/// extremely frequently and thus, their access to the definition of
-/// declaration must be fast.
-///
-/// @return the definition of the class.
-const class_decl*
-class_decl::get_naked_definition_of_declaration() const
-{return is_class_type(class_or_union::get_naked_definition_of_declaration());}
-
 /// Set the "is-struct" flag of the class.
 ///
 /// @param f the new value of the flag.
@@ -20938,14 +21049,16 @@ class_decl::operator==(const decl_base& other) const
       && get_is_declaration_only()
       && get_naked_definition_of_declaration())
     canonical_type =
-      get_naked_definition_of_declaration()->get_naked_canonical_type();
+      is_class_type
+      (get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   // Likewise for the other class.
   if (!other_canonical_type
       && op->get_is_declaration_only()
       && op->get_naked_definition_of_declaration())
     other_canonical_type =
-      op->get_naked_definition_of_declaration()->get_naked_canonical_type();
+      is_class_type
+      (op->get_naked_definition_of_declaration())->get_naked_canonical_type();
 
   if (canonical_type && other_canonical_type)
     return canonical_type == other_canonical_type;
@@ -23035,7 +23148,8 @@ hash_type(const type_base *t)
 	// The is a declaration-only class, so it has no canonical
 	// type; but then it's class definition has one.  Let's
 	// use that one.
-	return hash_type(cl->get_naked_definition_of_declaration());
+	return hash_type
+	  (is_class_type(cl->get_naked_definition_of_declaration()));
       else
 	{
 	  // The class really has no canonical type, let's use the
-- 
1.8.3.1


-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 06/11] Support incomplete enums in core and diff code.
  2020-07-08  9:22       ` Dodji Seketeli
@ 2020-07-08 10:39         ` Giuliano Procida
  2020-07-08 15:30           ` Dodji Seketeli
  0 siblings, 1 reply; 32+ messages in thread
From: Giuliano Procida @ 2020-07-08 10:39 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail

On Wed, 8 Jul 2020 at 10:22, Dodji Seketeli <dodji@seketeli.org> wrote:
>
> Hello Giuliano,
>
> Giuliano Procida <gprocida@google.com> a écrit:
>
> > Hi Dodji.
> >
> > Overall this looks like an excellent compromise. In terms of the
> > surgery on the type hierarchy, my main concerns would be that
> >
> > 1. things that are not class/union/enum but which fall under decl_base
> > continue to get the same treatment
>
> Agreed.
>
> > 2. old places where class/union had declaration-only manipulation and
> > new places where enums have the same both get the right down-casting
>
> Yes.
>
> > It looks like these are there. I have some further comments in-line,
> > nothing significant.
>
> Thanks.
>
> [...]
>
> >> +bool
> >> +has_decl_only_def_change(const decl_base_sptr& first,
> >> +                        const decl_base_sptr& second)
> >> +{
> >> +  if (!first || !second)
> >> +    return false;
> >> +
> >> +  decl_base_sptr f =
> >> +    look_through_decl_only(first);
> >> +  decl_base_sptr s =
> >> +    look_through_decl_only(second);
> >> +
> >> +  if (f->get_qualified_name() != s->get_qualified_name())
> >> +    return false;
> >> +
> >> +  return (f->get_is_declaration_only() != s->get_is_declaration_only());
> >
> > This return statement doesn't need the outer ( ).
>
> Fixed.
>
> [...]
>
> >>  /// Test if two @ref class_or_union_sptr are different just by the
> >>  /// fact that one is decl-only and the other one is defined.
> >>  ///
> >> @@ -956,6 +1026,31 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
> >>    return (f->get_is_declaration_only() != s->get_is_declaration_only());
> >
> > Same here on the return statement.
>
> Fixed.
>
> [...]
>
> >> +bool
> >> +has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
> >> +                             const enum_type_decl_sptr& second)
> >> +{
> >> +  if (!first || !second)
> >> +    return false;
> >> +
> >> +  enum_type_decl_sptr f = look_through_decl_only_enum(first);
> >> +  enum_type_decl_sptr s = look_through_decl_only_enum(second);
> >> +
> >> +  if (f->get_qualified_name() != s->get_qualified_name())
> >> +    return false;
> >> +
> >> +  return (f->get_is_declaration_only() != s->get_is_declaration_only());
> >
> > And again.
>
> Fixed.
>
> [...]
>
> >> @@ -3423,7 +3427,9 @@ struct decl_base::priv
> >>        is_artificial_(false),
> >>        has_anonymous_parent_(false),
> >>        context_(),
> >> -      visibility_(VISIBILITY_DEFAULT)
> >> +      visibility_(VISIBILITY_DEFAULT),
> >> +      naked_definition_of_declaration_(),
> >> +      is_declaration_only_()
> >
> > Would be clearer to say (false).
>
> Fixed.
>
> >>    {}
> >>
> >>    priv(interned_string name, const location& locus,
> >> @@ -3434,7 +3440,9 @@ struct decl_base::priv
> >>        name_(name),
> >>        qualified_name_(name),
> >>        linkage_name_(linkage_name),
> >> -      visibility_(vis)
> >> +      visibility_(vis),
> >> +      naked_definition_of_declaration_(),
> >> +      is_declaration_only_()
> >
> > Same here.
>
> Fixed.
>
> >>    {
> >>      is_anonymous_ = name_.empty();
> >>      has_anonymous_parent_ = false;
> >> @@ -3446,7 +3454,9 @@ struct decl_base::priv
> >>        has_anonymous_parent_(false),
> >>        location_(l),
> >>        context_(),
> >> -      visibility_(VISIBILITY_DEFAULT)
> >> +      visibility_(VISIBILITY_DEFAULT),
> >> +      naked_definition_of_declaration_(),
> >> +      is_declaration_only_()
> >
> > And again.
>
> Fixed.
>
> [...]
>
> >> +/// Set a flag saying if the @ref enum_type_decl is a declaration-only
> >> +/// @ref enum_type_decl.
> >> +///
> >> +/// @param f true if the @ref enum_type_decl is a decalaration-only
> >
> > Typo: decalaration / declaration.
>
> Fixed.
>
> [...]
>
> >> +/// Test if a type is a enum. This function looks through typedefs.
> >
> > Typo: a enum / an enum.
>
> Fixed.
>
> [...]
>
> >> +/// Test if a type is a enum. This function looks through typedefs.
> >
> > Same typo.
>
> Fixed.
>
> >> +///
> >> +/// @parm t the type to consider.
> >> +///
> >> +/// @return the enum_decl if @p t is a enum_decl or null otherwise.
> >
> > Technically a typo: a enum_decl / an enum_decl.
> > I'm not sure how it will render if you @ref the types.
>
> Fixed.
>
> >> +enum_type_decl_sptr
> >> +is_compatible_with_enum_type(const decl_base_sptr& t)
> >> +{return is_compatible_with_enum_type(is_type(t));}
> >> +
> >>  /// Test if a decl is an enum_type_decl
> >>  ///
> >>  /// @param d the decl to test for.
> >> @@ -8270,24 +8386,19 @@ is_method_type(type_or_decl_base* t)
> >>  /// @param the_klass the class (or union) to consider.
> >
> > Parameter is the_class.
>
> Fixed.
>
> >>  ///
> >>  /// @return either the definition of the class, or the class itself.
> >> +class_or_union*
> >> +look_through_decl_only_class(class_or_union* the_class)
> >> +{return is_class_or_union_type(look_through_decl_only(the_class));}
> >> +
> >> +/// If a class (or union) is a decl-only class, get its definition.
> >> +/// Otherwise, just return the initial class.
> >> +///
> >> +/// @param the_klass the class (or union) to consider.
> >
> > Same here.
>
> Fixed.
>
> [...]
>
>
> >> +decl_base_sptr
> >> +look_through_decl_only(const decl_base& d)
> >> +{
> >> +  decl_base_sptr decl;
> >> +  if (d.get_is_declaration_only())
> >> +    decl = d.get_definition_of_declaration();
> >> +
> >> +  if (!decl)
> >> +    return decl;
> >> +
> >> +  while (decl
> >> +        && decl->get_is_declaration_only()
> >> +        && decl->get_definition_of_declaration())
> >> +    decl = decl->get_definition_of_declaration();
> >> +
> >> +  ABG_ASSERT(decl);
> >> +  return decl;
> >
> > I had a suspicion that this code could be simplified a while ago.
> >
> > You should be able to simplify it to (something like):
> >
> > look_through_decl_only_class(class_or_union_sptr klass)
> > {
> >   if (!klass)
> >     return klass;
> >   while (klass->get_is_declaration_only()
> >          && klass->get_definition_of_declaration())
> >     klass = klass->get_definition_of_declaration();
> >   return klass;
> > }
> >
> > This is two things:
> > 1. The function is simpler if it takes a (shared) pointer argument.
> > You probably don't need the other overload.
>
> Actually, I prefer keeping the function that takes reference.  It's
> reused in the overload that takes a pointer.  Also, I have some
> test/play programs on the side that use types instantiated on the stack
> etc and that make use of these.  So they are useful in general, I think.
>
> > 2. You don't need to retest decl on every loop or assert it at the
> > end, just check once at the top as the loop condition preserves the
> > invariant.
>
> Yes, you are correct.  I have made this change in the updated patch.
> Thanks.
>
> [...]
>
> [...]
>
> >> +/// Look into a given corpus to find the enum type*s* that have a
> >> +/// given qualified name.
> >> +///
> >> +/// @param qualified_name the qualified name of the type to look for.
> >> +///
> >> +/// @param corp the corpus to look into.
> >> +///
> >> +/// @return the vector of enum types that which name is @p qualified_name.
> >
> > Suggest: "that which name is" -> "named" (or "which have the name")
> > (and again, below)
>
> Of course.  Fixed.
>
> [...]
>
> Please find below an updated patch that is present in my updated
> dodji/incomp-enum branch.
>
> Thanks.
>
>
> From 377b577cbbdc313e78b58631f5fb9bcc2c913a25 Mon Sep 17 00:00:00 2001
> From: Giuliano Procida <gprocida@google.com>
> Date: Wed, 10 Jun 2020 12:59:35 +0100
> Subject: [PATCH 1/4] Support incomplete enums in core and diff code.
>
> This is an initial implementation of the support for incomplete, also
> known as forward-declared, enum types. I've not made any attempt to
> refactor or share logic with the struct/union code.
>
>         * include/abg-comp-filter.h (has_decl_only_def_change) : Declare
>         New function.
>         * src/abg-comp-filter.cc (there_is_a_decl_only_enum): Define new
>         static function and ...
>         (type_size_changed): ... use it here.
>         (has_decl_only_def_change): Define new function and ...
>         (categorize_harm{less, ful}_diff_node): ... use it here.
>         * include/abg-fwd.h (enums_type, decl_base_wptr): Declare new
>         typedefs.
>         (look_through_decl_only_class): Declare new overload for
>         class_or_union*.
>         (is_compatible_with_enum_type, is_compatible_with_enum_type)
>         (look_through_decl_only, lookup_enum_types, lookup_enum_types):
>         Declare new functions.
>         * include/abg-ir.h (decl_base::{get_is_declaration_only,
>         set_is_declaration_only, set_definition_of_declaration,
>         get_definition_of_declaration,
>         get_naked_definition_of_declaration}): Declare new member
>         functions.  They were moved here from the class_or_union class.
>         (class_or_union::{get_earlier_declaration,
>         set_earlier_declaration, get_definition_of_declaration,
>         set_definition_of_declaration,
>         get_naked_definition_of_declaration, get_is_declaration_only,
>         set_is_declaration_only}): Remove these member functions.
>         * src/abg-ir.cc (decl_base::priv::{declaration_,
>         definition_of_declaration_, naked_definition_of_declaration_,
>         is_declaration_only_}): Define data members.  Moved here from
>         class_or_union.
>         (decl_base::priv::priv): Adjust to initialize the new data
>         members.
>         (decl_base::{get_earlier_declaration, set_earlier_declaration,
>         get_definition_of_declaration,
>         get_naked_definition_of_declaration, get_is_declaration_only,
>         set_is_declaration_only, set_definition_of_declaration}): Define
>         member functions.
>         (operator|): In the overload for (change_kind, change_kind),
>         adjust the return type of the call to
>         decl_base::get_definition_of_declaration.
>         (look_through_decl_only): Define new function.
>         (look_through_decl_only_class): Adjust.
>         (look_through_decl_only_enum): Likewise.
>         (maybe_update_types_lookup_map<class_decl>): Adjust return type of
>         call to decl_base::get_definition_of_declaration.
>         (types_defined_same_linux_kernel_corpus_public): Use
>         look_through_decl_only_class rather than open coding it.
>         (class_or_union::priv::{declaration_, definition_of_declaration_,
>         naked_definition_of_declaration_, is_declaration_only_}): Remove
>         these data members.  They are now carried by decl_base::priv.
>         (class_or_union::{g,s}et_alignment_in_bits): Adjust.
>         (class_or_union::{g,s}et_size_in_bits): Likewise.
>         (class_or_union::operator==): Likewise.
>         (equals): Adjust the overload for class_or_union.
>         (is_compatible_with_enum_type)
>         * src/abg-comparison.cc (try_to_diff<class_decl>): Adjust the
>         return type of decl_base::get_definition_of_declaration.
>         (leaf_diff_node_marker_visitor::visit_begin): Use
>         filtering::has_decl_only_def_change rather than
>         filtering::has_class_decl_only_def_change.  Decl-only changes to
>         enums (or any other type really) will thus not be recorded as leaf
>         changes.
>         * src/abg-dwarf-reader.cc (get_scope_for_die): Adjust return type
>         of decl_base::get_definition_of_declaration.
>         * src/abg-default-reporter.cc (default_reporter::report): Report
>         enum decl-only <-> definition changes.
>         * src/abg-hash.cc (class_or_union::hash::operator()): In the
>         overload for class_or_union& adjust the return type for
>         decl_base::get_definition_of_declaration.
>
> Signed-off-by: Giuliano Procida <gprocida@google.com>
> Signed-off-by: Dodji Seketeli <dodji@redhat.com>
> ---
>  include/abg-comp-filter.h   |  14 ++
>  include/abg-fwd.h           |  36 ++++
>  include/abg-ir.h            |  48 ++---
>  src/abg-comp-filter.cc      | 133 ++++++++++++-
>  src/abg-comparison.cc       |  10 +-
>  src/abg-default-reporter.cc |  19 ++
>  src/abg-dwarf-reader.cc     |   3 +-
>  src/abg-hash.cc             |   3 +-
>  src/abg-ir.cc               | 472 +++++++++++++++++++++++++++-----------------
>  9 files changed, 519 insertions(+), 219 deletions(-)
>
> diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h
> index 8113003..556bad4 100644
> --- a/include/abg-comp-filter.h
> +++ b/include/abg-comp-filter.h
> @@ -65,13 +65,27 @@ bool
>  is_decl_only_class_with_size_change(const diff *diff);
>
>  bool
> +has_decl_only_def_change(const decl_base_sptr& first,
> +                        const decl_base_sptr& second);
> +
> +bool
> +has_decl_only_def_change(const diff *d);
> +
> +bool
>  has_class_decl_only_def_change(const class_or_union_sptr& first,
>                                const class_or_union_sptr& second);
>
>  bool
> +has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
> +                             const enum_type_decl_sptr& second);
> +
> +bool
>  has_class_decl_only_def_change(const diff *diff);
>
>  bool
> +has_enum_decl_only_def_change(const diff *diff);
> +
> +bool
>  has_basic_type_name_change(const diff *);
>
>  bool
> diff --git a/include/abg-fwd.h b/include/abg-fwd.h
> index f23f4a4..bfd9f88 100644
> --- a/include/abg-fwd.h
> +++ b/include/abg-fwd.h
> @@ -155,6 +155,12 @@ class enum_type_decl;
>  /// Convenience typedef for shared pointer to a @ref enum_type_decl.
>  typedef shared_ptr<enum_type_decl> enum_type_decl_sptr;
>
> +/// Convenience typedef for a vector of @ref enum_type_decl_sptr
> +typedef vector<enum_type_decl_sptr> enums_type;
> +
> +/// Convenience typedef for a weak pointer to a @ref decl_base.
> +typedef weak_ptr<decl_base> decl_base_wptr;
> +
>  class class_or_union;
>
>  typedef shared_ptr<class_or_union> class_or_union_sptr;
> @@ -424,6 +430,12 @@ typedef_decl*
>  is_typedef(type_base*);
>
>  enum_type_decl_sptr
> +is_compatible_with_enum_type(const type_base_sptr&);
> +
> +enum_type_decl_sptr
> +is_compatible_with_enum_type(const decl_base_sptr&);
> +
> +enum_type_decl_sptr
>  is_enum_type(const type_or_decl_base_sptr&);
>
>  const enum_type_decl*
> @@ -513,6 +525,24 @@ look_through_decl_only_class(const class_or_union&);
>  class_or_union_sptr
>  look_through_decl_only_class(class_or_union_sptr);
>
> +class_or_union*
> +look_through_decl_only_class(class_or_union*);
> +
> +enum_type_decl_sptr
> +look_through_decl_only_enum(const enum_type_decl&);
> +
> +enum_type_decl_sptr
> +look_through_decl_only_enum(enum_type_decl_sptr);
> +
> +decl_base_sptr
> +look_through_decl_only(const decl_base&);
> +
> +decl_base*
> +look_through_decl_only(decl_base*);
> +
> +decl_base_sptr
> +look_through_decl_only(const decl_base_sptr&);
> +
>  var_decl*
>  is_var_decl(const type_or_decl_base*);
>
> @@ -1085,6 +1115,12 @@ lookup_enum_type(const string&, const corpus&);
>  enum_type_decl_sptr
>  lookup_enum_type(const interned_string&, const corpus&);
>
> +const type_base_wptrs_type*
> +lookup_enum_types(const interned_string&, const corpus&);
> +
> +const type_base_wptrs_type*
> +lookup_enum_types(const string&, const corpus&);
> +
>  enum_type_decl_sptr
>  lookup_enum_type_per_location(const interned_string&, const corpus&);
>
> diff --git a/include/abg-ir.h b/include/abg-ir.h
> index c2b66c4..5b13dc9 100644
> --- a/include/abg-ir.h
> +++ b/include/abg-ir.h
> @@ -1553,6 +1553,27 @@ public:
>    void
>    set_visibility(visibility v);
>
> +  const decl_base_sptr
> +  get_earlier_declaration() const;
> +
> +  void
> +  set_earlier_declaration(const decl_base_sptr&);
> +
> +  const decl_base_sptr
> +  get_definition_of_declaration() const;
> +
> +  void
> +  set_definition_of_declaration(const decl_base_sptr&);
> +
> +  const decl_base*
> +  get_naked_definition_of_declaration() const;
> +
> +  bool
> +  get_is_declaration_only() const;
> +
> +  void
> +  set_is_declaration_only(bool f);
> +
>    friend type_base_sptr
>    canonicalize(type_base_sptr);
>
> @@ -3776,27 +3797,6 @@ public:
>    void
>    set_naming_typedef(const typedef_decl_sptr&);
>
> -  bool
> -  get_is_declaration_only() const;
> -
> -  void
> -  set_is_declaration_only(bool f);
> -
> -  void
> -  set_definition_of_declaration(class_or_union_sptr);
> -
> -  const class_or_union_sptr
> -  get_definition_of_declaration() const;
> -
> -  const class_or_union*
> -  get_naked_definition_of_declaration() const;
> -
> -  decl_base_sptr
> -  get_earlier_declaration() const;
> -
> -  void
> -  set_earlier_declaration(decl_base_sptr declaration);
> -
>   void
>    insert_member_type(type_base_sptr t,
>                      declarations::iterator before);
> @@ -4020,12 +4020,6 @@ public:
>    class_decl(const environment* env, const string& name, bool is_struct,
>              bool is_declaration_only = true);
>
> -  const class_decl_sptr
> -  get_definition_of_declaration() const;
> -
> -  const class_decl*
> -  get_naked_definition_of_declaration() const;
> -
>    virtual string
>    get_pretty_representation(bool internal = false,
>                             bool qualified_name = true) const;
> diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
> index 702d223..0b0fbe4 100644
> --- a/src/abg-comp-filter.cc
> +++ b/src/abg-comp-filter.cc
> @@ -118,6 +118,25 @@ there_is_a_decl_only_class(const class_decl_sptr& class1,
>    return false;
>  }
>
> +/// Test if there is a enum that is declaration-only among the two
> +/// enums in parameter.
> +///
> +/// @param enum1 the first enum to consider.
> +///
> +/// @param enum2 the second enum to consider.
> +///
> +/// @return true if either enums are declaration-only, false
> +/// otherwise.
> +static bool
> +there_is_a_decl_only_enum(const enum_type_decl_sptr& enum1,
> +                         const enum_type_decl_sptr& enum2)
> +{
> +  if ((enum1 && enum1->get_is_declaration_only())
> +      || (enum2 && enum2->get_is_declaration_only()))
> +    return true;
> +  return false;
> +}
> +
>  /// Test if the diff involves a declaration-only class.
>  ///
>  /// @param diff the class diff to consider.
> @@ -146,7 +165,9 @@ type_size_changed(const type_base_sptr f, const type_base_sptr s)
>        || f->get_size_in_bits() == 0
>        || s->get_size_in_bits() == 0
>        || there_is_a_decl_only_class(is_compatible_with_class_type(f),
> -                                   is_compatible_with_class_type(s)))
> +                                   is_compatible_with_class_type(s))
> +      || there_is_a_decl_only_enum(is_compatible_with_enum_type(f),
> +                                  is_compatible_with_enum_type(s)))
>      return false;
>
>    return f->get_size_in_bits() != s->get_size_in_bits();
> @@ -893,10 +914,8 @@ is_decl_only_class_with_size_change(const class_or_union_sptr& first,
>    if (!first || !second)
>      return false;
>
> -  class_or_union_sptr f =
> -    look_through_decl_only_class(first);
> -  class_or_union_sptr s =
> -    look_through_decl_only_class(second);
> +  class_or_union_sptr f = look_through_decl_only_class(first);
> +  class_or_union_sptr s = look_through_decl_only_class(second);
>
>    return is_decl_only_class_with_size_change(*f, *s);
>  }
> @@ -929,6 +948,57 @@ is_decl_only_class_with_size_change(const diff *diff)
>    return is_decl_only_class_with_size_change(f, s);
>  }
>
> +/// Test if two @ref decl_base_sptr are different just by the
> +/// fact that one is decl-only and the other one is defined.
> +///
> +/// @param first the first decl to consider.
> +///
> +/// @param second the second decl to consider.
> +///
> +/// @return true iff the two arguments are different just by the fact
> +/// that one is decl-only and the other one is defined.
> +bool
> +has_decl_only_def_change(const decl_base_sptr& first,
> +                        const decl_base_sptr& second)
> +{
> +  if (!first || !second)
> +    return false;
> +
> +  decl_base_sptr f =
> +    look_through_decl_only(first);
> +  decl_base_sptr s =
> +    look_through_decl_only(second);
> +
> +  if (f->get_qualified_name() != s->get_qualified_name())
> +    return false;
> +
> +  return f->get_is_declaration_only() != s->get_is_declaration_only();
> +}
> +
> +/// Test if a diff carries a change in which the two decls are
> +/// different by the fact that one is a decl-only and the other one is
> +/// defined.
> +///
> +/// @param diff the diff node to consider.
> +///
> +/// @return true if the diff carries a change in which the two decls
> +/// are different by the fact that one is a decl-only and the other
> +/// one is defined.
> +bool
> +has_decl_only_def_change(const diff *d)
> +{
> +  if (!d)
> +    return false;
> +
> +  decl_base_sptr f =
> +    look_through_decl_only(is_decl(d->first_subject()));
> +  decl_base_sptr s =
> +    look_through_decl_only(is_decl(d->second_subject()));
> +
> +  return has_decl_only_def_change(f, s);
> +}
> +
> +
>  /// Test if two @ref class_or_union_sptr are different just by the
>  /// fact that one is decl-only and the other one is defined.
>  ///
> @@ -953,7 +1023,32 @@ has_class_decl_only_def_change(const class_or_union_sptr& first,
>    if (f->get_qualified_name() != s->get_qualified_name())
>      return false;
>
> -  return (f->get_is_declaration_only() != s->get_is_declaration_only());
> +  return f->get_is_declaration_only() != s->get_is_declaration_only();
> +}
> +
> +/// Test if two @ref enum_sptr are different just by the
> +/// fact that one is decl-only and the other one is defined.
> +///
> +/// @param first the first enum to consider.
> +///
> +/// @param second the second enum to consider.
> +///
> +/// @return true iff the two arguments are different just by the fact
> +/// that one is decl-only and the other one is defined.
> +bool
> +has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
> +                             const enum_type_decl_sptr& second)
> +{
> +  if (!first || !second)
> +    return false;
> +
> +  enum_type_decl_sptr f = look_through_decl_only_enum(first);
> +  enum_type_decl_sptr s = look_through_decl_only_enum(second);
> +
> +  if (f->get_qualified_name() != s->get_qualified_name())
> +    return false;
> +
> +  return f->get_is_declaration_only() != s->get_is_declaration_only();
>  }
>
>  /// Test if a class_or_union_diff carries a change in which the two
> @@ -980,6 +1075,28 @@ has_class_decl_only_def_change(const diff *diff)
>    return has_class_decl_only_def_change(f, s);
>  }
>
> +/// Test if a enum_diff carries a change in which the two enums are
> +/// different by the fact that one is a decl-only and the other one is
> +/// defined.
> +///
> +/// @param diff the diff node to consider.
> +///
> +/// @return true if the enum_diff carries a change in which the two
> +/// enums are different by the fact that one is a decl-only and the
> +/// other one is defined.
> +bool
> +has_enum_decl_only_def_change(const diff *diff)
> +{
> +  const enum_diff *d = dynamic_cast<const enum_diff*>(diff);
> +  if (!d)
> +    return false;
> +
> +  enum_type_decl_sptr f = look_through_decl_only_enum(d->first_enum());
> +  enum_type_decl_sptr s = look_through_decl_only_enum(d->second_enum());
> +
> +  return has_enum_decl_only_def_change(f, s);
> +}
> +
>  /// Test if a diff node carries a basic type name change.
>  ///
>  /// @param d the diff node to consider.
> @@ -1517,7 +1634,8 @@ categorize_harmless_diff_node(diff *d, bool pre)
>        decl_base_sptr f = is_decl(d->first_subject()),
>         s = is_decl(d->second_subject());
>
> -      if (has_class_decl_only_def_change(d))
> +      if (has_class_decl_only_def_change(d)
> +         || has_enum_decl_only_def_change(d))
>         category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY;
>
>        if (access_changed(f, s))
> @@ -1608,6 +1726,7 @@ categorize_harmful_diff_node(diff *d, bool pre)
>        //
>        // TODO: be more specific -- not all size changes are harmful.
>        if (!has_class_decl_only_def_change(d)
> +         && !has_enum_decl_only_def_change(d)
>           && (type_size_changed(f, s)
>               || data_member_offset_changed(f, s)
>               || non_static_data_member_type_size_changed(f, s)
> diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
> index d0f1d21..b6f065f 100644
> --- a/src/abg-comparison.cc
> +++ b/src/abg-comparison.cc
> @@ -2827,13 +2827,15 @@ try_to_diff<class_decl>(const type_or_decl_base_sptr first,
>
>        if (f->get_is_declaration_only())
>         {
> -         class_decl_sptr f2 = f->get_definition_of_declaration();
> +         class_decl_sptr f2 =
> +           is_class_type (f->get_definition_of_declaration());
>           if (f2)
>             f = f2;
>         }
>        if (s->get_is_declaration_only())
>         {
> -         class_decl_sptr s2 = s->get_definition_of_declaration();
> +         class_decl_sptr s2 =
> +           is_class_type(s->get_definition_of_declaration());
>           if (s2)
>             s = s2;
>         }
> @@ -10953,8 +10955,8 @@ struct leaf_diff_node_marker_visitor : public diff_node_visitor
>         // typedef change which underlying type is an anonymous
>         // struct/union.
>         && !is_anonymous_class_or_union_diff(d)
> -       // Don't show decl-only-ness changes of classes either.
> -       && !filtering::has_class_decl_only_def_change(d)
> +       // Don't show decl-only-ness changes either.
> +       && !filtering::has_decl_only_def_change(d)
>         // Sometime, we can encounter artifacts of bogus DWARF that
>         // yield a diff node for a decl-only class (and empty class
>         // with the is_declaration flag set) that carries a non-zero
> diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
> index 2acb695..cbf8c2b 100644
> --- a/src/abg-default-reporter.cc
> +++ b/src/abg-default-reporter.cc
> @@ -99,6 +99,25 @@ default_reporter::report(const enum_diff& d, ostream& out,
>    enum_type_decl_sptr first = d.first_enum(), second = d.second_enum();
>
>    const diff_context_sptr& ctxt = d.context();
> +
> +  // Report enum decl-only <-> definition changes.
> +  if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
> +    if (filtering::has_enum_decl_only_def_change(first, second))
> +      {
> +       string was =
> +         first->get_is_declaration_only()
> +         ? " was a declaration-only enum type"
> +         : " was a defined enum type";
> +
> +       string is_now =
> +         second->get_is_declaration_only()
> +         ? " and is now a declaration-only enum type"
> +         : " and is now a defined enum type";
> +
> +       out << indent << "enum type " << name << was << is_now << "\n";
> +       return;
> +      }
> +
>    report_name_size_and_alignment_changes(first, second, ctxt,
>                                          out, indent);
>    maybe_report_diff_for_member(first, second, ctxt, out, indent);
> diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
> index ba4e750..db43aa7 100644
> --- a/src/abg-dwarf-reader.cc
> +++ b/src/abg-dwarf-reader.cc
> @@ -12315,7 +12315,8 @@ get_scope_for_die(read_context& ctxt,
>    class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d);
>    if (cl && cl->get_is_declaration_only())
>      {
> -      scope_decl_sptr scop (cl->get_definition_of_declaration());
> +      scope_decl_sptr scop  =
> +       dynamic_pointer_cast<scope_decl>(cl->get_definition_of_declaration());
>        if (scop)
>         s = scop;
>        else
> diff --git a/src/abg-hash.cc b/src/abg-hash.cc
> index c1cdc57..5d2861f 100644
> --- a/src/abg-hash.cc
> +++ b/src/abg-hash.cc
> @@ -635,7 +635,8 @@ class_or_union::hash::operator()(const class_or_union& t) const
>    if (t.get_is_declaration_only())
>      {
>        ABG_ASSERT(t.get_definition_of_declaration());
> -      size_t v = operator()(*t.get_definition_of_declaration());
> +      size_t v = operator()
> +       (*is_class_or_union_type(t.get_definition_of_declaration()));
>        return v;
>      }
>
> diff --git a/src/abg-ir.cc b/src/abg-ir.cc
> index a434ec6..15bf124 100644
> --- a/src/abg-ir.cc
> +++ b/src/abg-ir.cc
> @@ -3416,6 +3416,10 @@ struct decl_base::priv
>      interned_string    scoped_name_;
>    interned_string      linkage_name_;
>    visibility           visibility_;
> +  decl_base_sptr       declaration_;
> +  decl_base_wptr       definition_of_declaration_;
> +  decl_base*           naked_definition_of_declaration_;
> +  bool                 is_declaration_only_;
>
>    priv()
>      : in_pub_sym_tab_(false),
> @@ -3423,7 +3427,9 @@ struct decl_base::priv
>        is_artificial_(false),
>        has_anonymous_parent_(false),
>        context_(),
> -      visibility_(VISIBILITY_DEFAULT)
> +      visibility_(VISIBILITY_DEFAULT),
> +      naked_definition_of_declaration_(),
> +      is_declaration_only_(false)
>    {}
>
>    priv(interned_string name, const location& locus,
> @@ -3434,7 +3440,9 @@ struct decl_base::priv
>        name_(name),
>        qualified_name_(name),
>        linkage_name_(linkage_name),
> -      visibility_(vis)
> +      visibility_(vis),
> +      naked_definition_of_declaration_(),
> +      is_declaration_only_(false)
>    {
>      is_anonymous_ = name_.empty();
>      has_anonymous_parent_ = false;
> @@ -3446,7 +3454,9 @@ struct decl_base::priv
>        has_anonymous_parent_(false),
>        location_(l),
>        context_(),
> -      visibility_(VISIBILITY_DEFAULT)
> +      visibility_(VISIBILITY_DEFAULT),
> +      naked_definition_of_declaration_(),
> +      is_declaration_only_(false)
>    {}
>
>    ~priv()
> @@ -3881,6 +3891,80 @@ const interned_string&
>  decl_base::get_scoped_name() const
>  {return priv_->scoped_name_;}
>
> +/// If this @ref decl_base is a definition, get its earlier
> +/// declaration.
> +///
> +/// @return the earlier declaration of the class, if any.
> +const decl_base_sptr
> +decl_base::get_earlier_declaration() const
> +{return priv_->declaration_;}
> +
> +/// set the earlier declaration of this @ref decl_base definition.
> +///
> +/// @param d the earlier declaration to set.  Note that it's set only
> +/// if it's a pure declaration.
> +void
> +decl_base::set_earlier_declaration(const decl_base_sptr& d)
> +{
> +  if (d && d->get_is_declaration_only())
> +    priv_->declaration_ = d;
> +}
> +
> +
> +/// If this @ref decl_base is declaration-only, get its definition, if
> +/// any.
> +///
> +/// @return the definition of this decl-only @ref decl_base.
> +const decl_base_sptr
> +decl_base::get_definition_of_declaration() const
> +{return priv_->definition_of_declaration_.lock();}
> +
> +///  If this @ref decl_base is declaration-only, get its definition,
> +///  if any.
> +///
> +/// Note that this function doesn't return a smart pointer, but rather
> +/// the underlying pointer managed by the smart pointer.  So it's as
> +/// fast as possible.  This getter is to be used in code paths that
> +/// are proven to be performance hot spots; especially, when comparing
> +/// sensitive types like enums, classes or unions.  Those are compared
> +/// extremely frequently and thus, their access to the definition of
> +/// declaration must be fast.
> +///
> +/// @return the definition of the declaration.
> +const decl_base*
> +decl_base::get_naked_definition_of_declaration() const
> +{return priv_->naked_definition_of_declaration_;}
> +
> +/// Test if a @ref decl_base is a declaration-only decl.
> +///
> +/// @return true iff the current @ref decl_base is declaration-only.
> +bool
> +decl_base::get_is_declaration_only() const
> +{return priv_->is_declaration_only_;}
> +
> +/// Set a flag saying if the @ref enum_type_decl is a declaration-only
> +/// @ref enum_type_decl.
> +///
> +/// @param f true if the @ref enum_type_decl is a declaration-only
> +/// @ref enum_type_decl.
> +void
> +decl_base::set_is_declaration_only(bool f)
> +{
> +  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
> +
> +  priv_->is_declaration_only_ = f;
> +
> +  if (update_types_lookup_map)
> +    if (scope_decl* s = get_scope())
> +      {
> +       scope_decl::declarations::iterator i;
> +       if (s->find_iterator_for_member(this, i))
> +         maybe_update_types_lookup_map(*i);
> +       else
> +         ABG_ASSERT_NOT_REACHED;
> +      }
> +}
> +
>  change_kind
>  operator|(change_kind l, change_kind r)
>  {
> @@ -4236,7 +4320,7 @@ operator!=(const type_base_sptr& l, const type_base_sptr& r)
>
>  /// Tests if a declaration has got a scope.
>  ///
> -/// @param d the decalaration to consider.
> +/// @param d the declaration to consider.
>  ///
>  /// @return true if the declaration has got a scope, false otherwise.
>  bool
> @@ -4245,7 +4329,7 @@ has_scope(const decl_base& d)
>
>  /// Tests if a declaration has got a scope.
>  ///
> -/// @param d the decalaration to consider.
> +/// @param d the declaration to consider.
>  ///
>  /// @return true if the declaration has got a scope, false otherwise.
>  bool
> @@ -6686,7 +6770,7 @@ get_location(const decl_base_sptr& decl)
>        if (class_or_union_sptr c = is_class_or_union_type(decl))
>         if (c->get_is_declaration_only() && c->get_definition_of_declaration())
>           {
> -           c = c->get_definition_of_declaration();
> +           c = is_class_or_union_type(c->get_definition_of_declaration());
>             loc = c->get_location();
>           }
>      }
> @@ -7925,6 +8009,40 @@ typedef_decl*
>  is_typedef(type_base* t)
>  {return dynamic_cast<typedef_decl*>(t);}
>
> +/// Test if a type is an enum. This function looks through typedefs.
> +///
> +/// @parm t the type to consider.
> +///
> +/// @return the enum_decl if @p t is an @ref enum_decl or null
> +/// otherwise.
> +enum_type_decl_sptr
> +is_compatible_with_enum_type(const type_base_sptr& t)
> +{
> +  if (!t)
> +    return enum_type_decl_sptr();
> +
> +  // Normally we should strip typedefs entirely, but this is
> +  // potentially costly, especially on binaries with huge changesets
> +  // like the Linux Kernel.  So we just get the leaf types for now.
> +  //
> +  // Maybe there should be an option by which users accepts to pay the
> +  // CPU usage toll in exchange for finer filtering?
> +
> +  // type_base_sptr ty = strip_typedef(t);
> +  type_base_sptr ty = peel_typedef_type(t);;
> +  return is_enum_type(ty);
> +}
> +
> +/// Test if a type is an enum. This function looks through typedefs.
> +///
> +/// @parm t the type to consider.
> +///
> +/// @return the enum_decl if @p t is an @ref enum_decl or null
> +/// otherwise.
> +enum_type_decl_sptr
> +is_compatible_with_enum_type(const decl_base_sptr& t)
> +{return is_compatible_with_enum_type(is_type(t));}
> +
>  /// Test if a decl is an enum_type_decl
>  ///
>  /// @param d the decl to test for.
> @@ -8267,27 +8385,22 @@ is_method_type(type_or_decl_base* t)
>  /// If a class (or union) is a decl-only class, get its definition.
>  /// Otherwise, just return the initial class.
>  ///
> -/// @param the_klass the class (or union) to consider.
> +/// @param the_class the class (or union) to consider.
> +///
> +/// @return either the definition of the class, or the class itself.
> +class_or_union*
> +look_through_decl_only_class(class_or_union* the_class)
> +{return is_class_or_union_type(look_through_decl_only(the_class));}
> +
> +/// If a class (or union) is a decl-only class, get its definition.
> +/// Otherwise, just return the initial class.
> +///
> +/// @param the_class the class (or union) to consider.
>  ///
>  /// @return either the definition of the class, or the class itself.
>  class_or_union_sptr
>  look_through_decl_only_class(const class_or_union& the_class)
> -{
> -  class_or_union_sptr klass;
> -  if (the_class.get_is_declaration_only())
> -    klass = the_class.get_definition_of_declaration();
> -
> -  if (!klass)
> -    return klass;
> -
> -  while (klass
> -        && klass->get_is_declaration_only()
> -        && klass->get_definition_of_declaration())
> -    klass = klass->get_definition_of_declaration();
> -
> -  ABG_ASSERT(klass);
> -  return klass;
> -}
> +{return is_class_or_union_type(look_through_decl_only(the_class));}
>
>  /// If a class (or union) is a decl-only class, get its definition.
>  /// Otherwise, just return the initial class.
> @@ -8297,13 +8410,84 @@ look_through_decl_only_class(const class_or_union& the_class)
>  /// @return either the definition of the class, or the class itself.
>  class_or_union_sptr
>  look_through_decl_only_class(class_or_union_sptr klass)
> +{return is_class_or_union_type(look_through_decl_only(klass));}
> +
> +/// If an enum is a decl-only enum, get its definition.
> +/// Otherwise, just return the initial enum.
> +///
> +/// @param the_enum the enum to consider.
> +///
> +/// @return either the definition of the enum, or the enum itself.
> +enum_type_decl_sptr
> +look_through_decl_only_enum(const enum_type_decl& the_enum)
> +{return is_enum_type(look_through_decl_only(the_enum));}
> +
> +/// If an enum is a decl-only enum, get its definition.
> +/// Otherwise, just return the initial enum.
> +///
> +/// @param enom the enum to consider.
> +///
> +/// @return either the definition of the enum, or the enum itself.
> +enum_type_decl_sptr
> +look_through_decl_only_enum(enum_type_decl_sptr enom)
> +{return is_enum_type(look_through_decl_only(enom));}
> +
> +/// If a decl is decl-only get its definition.  Otherwise, just return nil.
> +///
> +/// @param d the decl to consider.
> +///
> +/// @return either the definition of the decl, or nil.
> +decl_base_sptr
> +look_through_decl_only(const decl_base& d)
> +{
> +  decl_base_sptr decl;
> +  if (d.get_is_declaration_only())
> +    decl = d.get_definition_of_declaration();
> +
> +  if (!decl)
> +    return decl;
> +
> +  while (decl->get_is_declaration_only()
> +        && decl->get_definition_of_declaration())
> +    decl = decl->get_definition_of_declaration();
> +
> +  ABG_ASSERT(decl);

The assert is still here (and redundant - to be honest, the compiler
may be able to work this out for itself).

I didn't spot anything else, so all good.

Regards,
Giuliano.

> +  return decl;
> +}
> +
> +/// If a decl is decl-only enum, get its definition.  Otherwise, just
> +/// return the initial decl.
> +///
> +/// @param d the decl to consider.
> +///
> +/// @return either the definition of the enum, or the decl itself.
> +decl_base*
> +look_through_decl_only(decl_base* d)
> +{
> +  if (!d)
> +    return d;
> +
> +  decl_base* result = look_through_decl_only(*d).get();
> +  if (!result)
> +    result = d;
> +
> +  return result;
> +}
> +
> +/// If a decl is decl-only get its definition.  Otherwise, just return nil.
> +///
> +/// @param d the decl to consider.
> +///
> +/// @return either the definition of the decl, or nil.
> +decl_base_sptr
> +look_through_decl_only(const decl_base_sptr& d)
>  {
> -  if (!klass)
> -    return klass;
> +  if (!d)
> +    return d;
>
> -  class_or_union_sptr result = look_through_decl_only_class(*klass);
> +  decl_base_sptr result = look_through_decl_only(*d);
>    if (!result)
> -    result = klass;
> +    result = d;
>
>    return result;
>  }
> @@ -8784,7 +8968,7 @@ lookup_union_type_per_location(const string& loc, const corpus& corp)
>    return lookup_union_type_per_location(env->intern(loc), corp);
>  }
>
> -/// Lookup a enum type from a translation unit.
> +/// Lookup an enum type from a translation unit.
>  ///
>  /// This is done by looking the type up in the type map that is
>  /// maintained in the translation unit.  So this is as fast as
> @@ -8802,7 +8986,7 @@ lookup_enum_type(const interned_string& type_name, const translation_unit& tu)
>                                             tu.get_types().enum_types());
>  }
>
> -/// Lookup a enum type from a translation unit.
> +/// Lookup an enum type from a translation unit.
>  ///
>  /// This is done by looking the type up in the type map that is
>  /// maintained in the translation unit.  So this is as fast as
> @@ -10004,7 +10188,7 @@ lookup_class_type(const interned_string& qualified_name, const corpus& corp)
>  ///
>  /// @param corp the corpus to look into.
>  ///
> -/// @return the vector of class types that which name is @p qualified_name.
> +/// @return the vector of class types named @p qualified_name.
>  const type_base_wptrs_type *
>  lookup_class_types(const interned_string& qualified_name, const corpus& corp)
>  {
> @@ -10103,7 +10287,7 @@ lookup_union_type(const string& type_name, const corpus& corp)
>    return lookup_union_type(s, corp);
>  }
>
> -/// Look into a given corpus to find a enum type which has the same
> +/// Look into a given corpus to find an enum type which has the same
>  /// qualified name as a given enum type.
>  ///
>  /// If the per-corpus type map is non-empty (because the corpus allows
> @@ -10166,6 +10350,37 @@ lookup_enum_type(const interned_string& qualified_name, const corpus& corp)
>    return result;
>  }
>
> +/// Look into a given corpus to find the enum type*s* that have a
> +/// given qualified name.
> +///
> +/// @param qualified_name the qualified name of the type to look for.
> +///
> +/// @param corp the corpus to look into.
> +///
> +/// @return the vector of enum types that which name is @p qualified_name.
> +const type_base_wptrs_type *
> +lookup_enum_types(const interned_string& qualified_name, const corpus& corp)
> +{
> +  const istring_type_base_wptrs_map_type& m = corp.get_types().enum_types();
> +
> +  return lookup_types_in_map(qualified_name, m);
> +}
> +
> +/// Look into a given corpus to find the enum type*s* that have a
> +/// given qualified name.
> +///
> +/// @param qualified_name the qualified name of the type to look for.
> +///
> +/// @param corp the corpus to look into.
> +///
> +/// @return the vector of enum types that which name is @p qualified_name.
> +const type_base_wptrs_type*
> +lookup_enum_types(const string& qualified_name, const corpus& corp)
> +{
> +  interned_string s = corp.get_environment()->intern(qualified_name);
> +  return lookup_enum_types(s, corp);
> +}
> +
>  /// Look up an @ref enum_type_decl from a given corpus, by its location.
>  ///
>  /// @param loc the location to consider.
> @@ -10767,7 +10982,8 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type,
>    bool update_qname_map = true;
>    if (type->get_is_declaration_only())
>      {
> -      if (class_decl_sptr def = class_type->get_definition_of_declaration())
> +      if (class_decl_sptr def =
> +         is_class_type(class_type->get_definition_of_declaration()))
>         type = def;
>        else
>         update_qname_map = false;
> @@ -11683,10 +11899,8 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
>
>    // Look through declaration-only types.  That is, get the associated
>    // definition type.
> -  if (c1 && c1->get_is_declaration_only())
> -    c1 = c1->get_definition_of_declaration().get();
> -  if (c2 && c2->get_is_declaration_only())
> -    c2 = c2->get_definition_of_declaration().get();
> +  c1 = look_through_decl_only_class(c1);
> +  c2 = look_through_decl_only_class(c2);
>
>    if (c1 && c2)
>      {
> @@ -12079,6 +12293,23 @@ canonicalize(type_base_sptr t)
>    return canonical;
>  }
>
> +
> +/// Set the definition of this declaration-only @ref decl_base.
> +///
> +/// @param d the new definition to set.
> +void
> +decl_base::set_definition_of_declaration(const decl_base_sptr& d)
> +{
> +  ABG_ASSERT(get_is_declaration_only());
> +  priv_->definition_of_declaration_ = d;
> +  priv_->definition_of_declaration_ = d;
> +  if (type_base *t = is_type(this))
> +    if (type_base_sptr canonical_type = is_type(d)->get_canonical_type())
> +      t->priv_->canonical_type = canonical_type;
> +
> +  priv_->naked_definition_of_declaration_ = const_cast<decl_base*>(d.get());
> +}
> +
>  /// The constructor of @ref type_base.
>  ///
>  /// @param s the size of the type, in bits.
> @@ -14978,7 +15209,6 @@ class enum_type_decl::priv
>    priv();
>
>  public:
> -
>    priv(type_base_sptr underlying_type,
>         enumerators& enumerators)
>      : underlying_type_(underlying_type),
> @@ -17987,9 +18217,6 @@ function_decl::parameter::get_pretty_representation(bool internal,
>  struct class_or_union::priv
>  {
>    typedef_decl_wptr            naming_typedef_;
> -  decl_base_sptr               declaration_;
> -  class_or_union_wptr          definition_of_declaration_;
> -  class_or_union*              naked_definition_of_declaration_;
>    member_types                 member_types_;
>    data_members                 data_members_;
>    data_members                 non_static_data_members_;
> @@ -18001,21 +18228,16 @@ struct class_or_union::priv
>    string_mem_fn_ptr_map_type   signature_2_mem_fn_map_;
>    member_function_templates    member_function_templates_;
>    member_class_templates       member_class_templates_;
> -  bool                         is_declaration_only_;
>
>    priv()
> -    : naked_definition_of_declaration_(),
> -      is_declaration_only_(false)
>    {}
>
>    priv(class_or_union::member_types& mbr_types,
>         class_or_union::data_members& data_mbrs,
>         class_or_union::member_functions& mbr_fns)
> -    : naked_definition_of_declaration_(),
> -      member_types_(mbr_types),
> +    : member_types_(mbr_types),
>        data_members_(data_mbrs),
> -      member_functions_(mbr_fns),
> -      is_declaration_only_(false)
> +      member_functions_(mbr_fns)
>    {
>      for (data_members::const_iterator i = data_members_.begin();
>          i != data_members_.end();
> @@ -18024,11 +18246,6 @@ struct class_or_union::priv
>         non_static_data_members_.push_back(*i);
>    }
>
> -  priv(bool is_declaration_only)
> -    : naked_definition_of_declaration_(),
> -      is_declaration_only_(is_declaration_only)
> -  {}
> -
>    /// Mark a class or union or union as being currently compared using
>    /// the class_or_union== operator.
>    ///
> @@ -18244,8 +18461,10 @@ class_or_union::class_or_union(const environment* env, const string& name,
>      decl_base(env, name, location(), name),
>      type_base(env, 0, 0),
>      scope_type_decl(env, name, 0, 0, location()),
> -    priv_(new priv(is_declaration_only))
> -{}
> +    priv_(new priv)
> +{
> +  set_is_declaration_only(is_declaration_only);
> +}
>
>  /// This implements the ir_traversable_base::traverse pure virtual
>  /// function.
> @@ -18465,7 +18684,8 @@ size_t
>  class_or_union::get_alignment_in_bits() const
>  {
>    if (get_is_declaration_only() && get_definition_of_declaration())
> -    return get_definition_of_declaration()->get_alignment_in_bits();
> +    return is_class_or_union_type
> +      (get_definition_of_declaration())->get_alignment_in_bits();
>
>     return type_base::get_alignment_in_bits();
>  }
> @@ -18480,7 +18700,8 @@ void
>  class_or_union::set_alignment_in_bits(size_t a)
>  {
>    if (get_is_declaration_only() && get_definition_of_declaration())
> -    get_definition_of_declaration()->set_alignment_in_bits(a);
> +    is_class_or_union_type
> +      (get_definition_of_declaration()) ->set_alignment_in_bits(a);
>    else
>      type_base::set_alignment_in_bits(a);
>  }
> @@ -18495,7 +18716,8 @@ void
>  class_or_union::set_size_in_bits(size_t s)
>  {
>    if (get_is_declaration_only() && get_definition_of_declaration())
> -    get_definition_of_declaration()->set_size_in_bits(s);
> +    is_class_or_union_type
> +      (get_definition_of_declaration())->set_size_in_bits(s);
>    else
>      type_base::set_size_in_bits(s);
>  }
> @@ -18510,42 +18732,12 @@ size_t
>  class_or_union::get_size_in_bits() const
>  {
>    if (get_is_declaration_only() && get_definition_of_declaration())
> -    return get_definition_of_declaration()->get_size_in_bits();
> +    return is_class_or_union_type
> +      (get_definition_of_declaration())->get_size_in_bits();
>
>    return type_base::get_size_in_bits();
>  }
>
> -/// Test if a @ref class_or_union is a declaration-only @ref
> -/// class_or_union.
> -///
> -/// @return true iff the current @ref class_or_union is a
> -/// declaration-only @ref class_or_union.
> -bool
> -class_or_union::get_is_declaration_only() const
> -{return priv_->is_declaration_only_;}
> -
> -/// Set a flag saying if the @ref class_or_union is a declaration-only
> -/// @ref class_or_union.
> -///
> -/// @param f true if the @ref class_or_union is a decalaration-only
> -/// @ref class_or_union.
> -void
> -class_or_union::set_is_declaration_only(bool f)
> -{
> -  bool update_types_lookup_map = !f && priv_->is_declaration_only_;
> -
> -  priv_->is_declaration_only_ = f;
> -
> -  if (update_types_lookup_map)
> -    if (scope_decl* s = get_scope())
> -      {
> -       declarations::iterator i;
> -       if (s->find_iterator_for_member(this, i))
> -         maybe_update_types_lookup_map(*i);
> -       else
> -         ABG_ASSERT_NOT_REACHED;
> -      }
> -}
>
>  /// Getter for the naming typedef of the current class.
>  ///
> @@ -18577,64 +18769,6 @@ class_or_union::set_naming_typedef(const typedef_decl_sptr& typedef_type)
>    priv_->naming_typedef_ = typedef_type;
>  }
>
> -/// Set the definition of this declaration-only @ref class_or_union.
> -///
> -/// @param d the new definition to set.
> -void
> -class_or_union::set_definition_of_declaration(class_or_union_sptr d)
> -{
> -  ABG_ASSERT(get_is_declaration_only());
> -  priv_->definition_of_declaration_ = d;
> -  if (d->get_canonical_type())
> -    type_base::priv_->canonical_type = d->get_canonical_type();
> -
> -  priv_->naked_definition_of_declaration_ = d.get();
> -}
> -
> -/// If this @ref class_or_union_sptr is declaration-only, get its
> -/// definition, if any.
> -///
> -/// @return the definition of this decl-only class.
> -const class_or_union_sptr
> -class_or_union::get_definition_of_declaration() const
> -{return priv_->definition_of_declaration_.lock();}
> -
> -///  If this @ref class_or_union is declaration-only, get its
> -///  definition, if any.
> -///
> -/// Note that this function doesn't return a smart pointer, but rather
> -/// the underlying pointer managed by the smart pointer.  So it's as
> -/// fast as possible.  This getter is to be used in code paths that
> -/// are proven to be performance hot spots; especially, when comparing
> -/// sensitive types like class or unions.  Those are compared
> -/// extremely frequently and thus, their access to the definition of
> -/// declaration must be fast.
> -///
> -/// @return the definition of the class.
> -const class_or_union*
> -class_or_union::get_naked_definition_of_declaration() const
> -{return priv_->naked_definition_of_declaration_;}
> -
> -/// If this @ref class_or_union_sptr is a definitin, get its earlier
> -/// declaration.
> -///
> -/// @return the earlier declaration of the class, if any.
> -decl_base_sptr
> -class_or_union::get_earlier_declaration() const
> -{return priv_->declaration_;}
> -
> -/// set the earlier declaration of this @ref class_or_union definition.
> -///
> -/// @param declaration the earlier declaration to set.  Note that it's
> -/// set only if it's a pure declaration.
> -void
> -class_or_union::set_earlier_declaration(decl_base_sptr declaration)
> -{
> -  class_or_union_sptr cl = dynamic_pointer_cast<class_or_union>(declaration);
> -  if (cl && cl->get_is_declaration_only())
> -    priv_->declaration_ = declaration;
> -}
> -
>  /// Get the member types of this @ref class_or_union.
>  ///
>  /// @return a vector of the member types of this ref class_or_union.
> @@ -19082,15 +19216,16 @@ class_or_union::operator==(const decl_base& other) const
>    if (!canonical_type
>        && get_is_declaration_only()
>        && get_naked_definition_of_declaration())
> -    canonical_type =
> -      get_naked_definition_of_declaration()->get_naked_canonical_type();
> +    canonical_type = is_class_or_union_type
> +      (get_naked_definition_of_declaration())->get_naked_canonical_type();
>
>    // Likewise for the other class.
>    if (!other_canonical_type
>        && op->get_is_declaration_only()
>        && op->get_naked_definition_of_declaration())
>      other_canonical_type =
> -      op->get_naked_definition_of_declaration()->get_naked_canonical_type();
> +      is_class_or_union_type
> +      (op->get_naked_definition_of_declaration())->get_naked_canonical_type();
>
>    if (canonical_type && other_canonical_type)
>      return canonical_type == other_canonical_type;
> @@ -19161,11 +19296,11 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
>    if (l_is_decl_only || r_is_decl_only)
>      {
>        const class_or_union* def1 = l_is_decl_only
> -       ? l.get_naked_definition_of_declaration()
> +       ? is_class_or_union_type(l.get_naked_definition_of_declaration())
>         : &l;
>
>        const class_or_union* def2 = r_is_decl_only
> -       ? r.get_naked_definition_of_declaration()
> +       ? is_class_or_union_type(r.get_naked_definition_of_declaration())
>         : &r;
>
>        if (!def1 || !def2)
> @@ -19784,30 +19919,6 @@ class_decl::on_canonical_type_set()
>      sort_virtual_member_functions(i->second);
>  }
>
> -///  If this @ref class_decl is declaration-only, get its definition,
> -///  if any.
> -///
> -/// @return the definition of the class.
> -const class_decl_sptr
> -class_decl::get_definition_of_declaration() const
> -{return is_class_type(class_or_union::get_definition_of_declaration());}
> -
> -///  If this @ref class_decl is declaration-only, get its definition,
> -///  if any.
> -///
> -/// Note that this function doesn't return a smart pointer, but rather
> -/// the underlying pointer managed by the smart pointer.  So it's as
> -/// fast as possible.  This getter is to be used in code paths that
> -/// are proven to be performance hot spots; especially, when comparing
> -/// sensitive types like class or unions.  Those are compared
> -/// extremely frequently and thus, their access to the definition of
> -/// declaration must be fast.
> -///
> -/// @return the definition of the class.
> -const class_decl*
> -class_decl::get_naked_definition_of_declaration() const
> -{return is_class_type(class_or_union::get_naked_definition_of_declaration());}
> -
>  /// Set the "is-struct" flag of the class.
>  ///
>  /// @param f the new value of the flag.
> @@ -20938,14 +21049,16 @@ class_decl::operator==(const decl_base& other) const
>        && get_is_declaration_only()
>        && get_naked_definition_of_declaration())
>      canonical_type =
> -      get_naked_definition_of_declaration()->get_naked_canonical_type();
> +      is_class_type
> +      (get_naked_definition_of_declaration())->get_naked_canonical_type();
>
>    // Likewise for the other class.
>    if (!other_canonical_type
>        && op->get_is_declaration_only()
>        && op->get_naked_definition_of_declaration())
>      other_canonical_type =
> -      op->get_naked_definition_of_declaration()->get_naked_canonical_type();
> +      is_class_type
> +      (op->get_naked_definition_of_declaration())->get_naked_canonical_type();
>
>    if (canonical_type && other_canonical_type)
>      return canonical_type == other_canonical_type;
> @@ -23035,7 +23148,8 @@ hash_type(const type_base *t)
>         // The is a declaration-only class, so it has no canonical
>         // type; but then it's class definition has one.  Let's
>         // use that one.
> -       return hash_type(cl->get_naked_definition_of_declaration());
> +       return hash_type
> +         (is_class_type(cl->get_naked_definition_of_declaration()));
>        else
>         {
>           // The class really has no canonical type, let's use the
> --
> 1.8.3.1
>
>
> --
>                 Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 06/11] Support incomplete enums in core and diff code.
  2020-07-08 10:39         ` Giuliano Procida
@ 2020-07-08 15:30           ` Dodji Seketeli
  0 siblings, 0 replies; 32+ messages in thread
From: Dodji Seketeli @ 2020-07-08 15:30 UTC (permalink / raw)
  To: Giuliano Procida; +Cc: libabigail

Giuliano Procida <gprocida@google.com> a écrit:

[...]

>> +/// If a decl is decl-only get its definition.  Otherwise, just return nil.
>> +///
>> +/// @param d the decl to consider.
>> +///
>> +/// @return either the definition of the decl, or nil.
>> +decl_base_sptr
>> +look_through_decl_only(const decl_base& d)
>> +{
>> +  decl_base_sptr decl;
>> +  if (d.get_is_declaration_only())
>> +    decl = d.get_definition_of_declaration();
>> +
>> +  if (!decl)
>> +    return decl;
>> +
>> +  while (decl->get_is_declaration_only()
>> +        && decl->get_definition_of_declaration())
>> +    decl = decl->get_definition_of_declaration();
>> +
>> +  ABG_ASSERT(decl);
>
> The assert is still here (and redundant - to be honest, the compiler
> may be able to work this out for itself).

Pff, right.  I removed it now, thanks.

> I didn't spot anything else, so all good.

Thanks.  I've just applied the series to master then.

Cheers,

-- 
		Dodji

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2020-07-08 15:30 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-10 11:59 [PATCH 00/11] Add incomplete enum support Giuliano Procida
2020-06-10 11:59 ` [PATCH 01/11] Missing initialisation of source local variable Giuliano Procida
2020-06-10 11:59 ` [PATCH 02/11] Improve code comments and whitespace Giuliano Procida
2020-06-29  8:26   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 03/11] Refactor d.context() as ctxt in report(enum_diff) Giuliano Procida
2020-06-29  8:54   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 04/11] Tidy build_enum_type state variables Giuliano Procida
2020-06-29  9:08   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 05/11] Rename declaration-definition change category Giuliano Procida
2020-06-29 16:17   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 06/11] Support incomplete enums in core and diff code Giuliano Procida
2020-07-06 11:14   ` Dodji Seketeli
     [not found]     ` <CAGvU0HkuOc74mfL9yLttK4Riwkrj9tmtc3VXxdHAsaCbn2153A@mail.gmail.com>
2020-07-08  9:22       ` Dodji Seketeli
2020-07-08 10:39         ` Giuliano Procida
2020-07-08 15:30           ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 07/11] Add invariant to enum_type_decl::set_is_declaration_only Giuliano Procida
2020-07-06 11:15   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 08/11] Support declaration-only enums in DWARF reader Giuliano Procida
2020-07-06 11:22   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 09/11] Support constructing opaque types for enums Giuliano Procida
2020-07-06 11:23   ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 10/11] Add declaration-only enums to XML reader/writer Giuliano Procida
2020-07-02 13:55   ` Dodji Seketeli
2020-07-02 15:09     ` Giuliano Procida
2020-07-06 11:05       ` Dodji Seketeli
2020-07-06 11:31   ` Dodji Seketeli
2020-07-07  8:31     ` Giuliano Procida
2020-07-07 14:57       ` Dodji Seketeli
2020-06-10 11:59 ` [PATCH 11/11] Add tests for declaration-only enums Giuliano Procida
2020-07-06 11:26   ` Dodji Seketeli
2020-07-01 13:36 ` [PATCH 00/11] Add incomplete enum support Dodji Seketeli
2020-07-01 15:18   ` Giuliano Procida

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).