xref: /aosp_15_r20/development/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "repr/abi_diff_helpers.h"
16 
17 #include "utils/header_abi_util.h"
18 
19 #include <android-base/strings.h>
20 #include <llvm/Support/raw_ostream.h>
21 
22 #include <unordered_set>
23 
24 
25 namespace header_checker {
26 namespace repr {
27 
28 
ConvertTypeIdToString(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)29 static std::string ConvertTypeIdToString(
30     const AbiElementMap<const TypeIR *> &type_graph,
31     const std::string &type_id) {
32   auto it = type_graph.find(type_id);
33   if (it != type_graph.end()) {
34     return it->second->GetName();
35   }
36   return "type-unexported";
37 }
38 
39 template <typename Container>
ReplaceReferencesOtherTypeIdWithName(const AbiElementMap<const TypeIR * > & type_graph,Container & to_fix_elements)40 static void ReplaceReferencesOtherTypeIdWithName(
41     const AbiElementMap<const TypeIR *> &type_graph,
42     Container &to_fix_elements) {
43   for (auto &element : to_fix_elements) {
44     element.SetReferencedType(
45         ConvertTypeIdToString(type_graph, element.GetReferencedType()));
46   }
47 }
48 
ReplaceEnumTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,EnumTypeIR * enum_type_ir)49 static void ReplaceEnumTypeIRTypeIdsWithTypeNames(
50     const AbiElementMap<const TypeIR *> &type_graph, EnumTypeIR *enum_type_ir) {
51   // Replace underlying type.
52   enum_type_ir->SetUnderlyingType(
53       ConvertTypeIdToString(type_graph, enum_type_ir->GetUnderlyingType()));
54 }
55 
ReplaceRecordTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,RecordTypeIR * record_type_ir)56 static void ReplaceRecordTypeIRTypeIdsWithTypeNames(
57     const AbiElementMap<const TypeIR *> &type_graph,
58     RecordTypeIR *record_type_ir) {
59   // Replace Fields
60   ReplaceReferencesOtherTypeIdWithName(type_graph,
61                                        record_type_ir->GetFields());
62   // Replace template parameters
63   ReplaceReferencesOtherTypeIdWithName(type_graph,
64                                        record_type_ir->GetTemplateElements());
65   // Replace bases
66   ReplaceReferencesOtherTypeIdWithName(type_graph,
67                                        record_type_ir->GetBases());
68 }
69 
ReplaceGlobalVarTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,GlobalVarIR * global_var_ir)70 static void ReplaceGlobalVarTypeIdsWithTypeNames(
71     const AbiElementMap<const TypeIR *> &type_graph,
72     GlobalVarIR *global_var_ir) {
73   // Replace referenced type id.
74   global_var_ir->SetReferencedType(
75       ConvertTypeIdToString(type_graph, global_var_ir->GetReferencedType()));
76 }
77 
ReplaceFunctionTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,FunctionIR * function_ir)78 static void ReplaceFunctionTypeIdsWithTypeNames(
79     const AbiElementMap<const TypeIR *> &type_graph, FunctionIR *function_ir) {
80   // Replace return type
81   function_ir->SetReturnType(
82       ConvertTypeIdToString(type_graph, function_ir->GetReturnType()));
83   // Replace function parameters
84   ReplaceReferencesOtherTypeIdWithName(type_graph,
85                                        function_ir->GetParameters());
86   // Replace function template parameters
87   ReplaceReferencesOtherTypeIdWithName(type_graph,
88                                        function_ir->GetTemplateElements());
89 }
90 
ReplaceTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,LinkableMessageIR * lm)91 void ReplaceTypeIdsWithTypeNames(
92     const AbiElementMap<const TypeIR *> &type_graph,
93     LinkableMessageIR *lm) {
94   switch (lm->GetKind()) {
95     case FunctionKind:
96       ReplaceFunctionTypeIdsWithTypeNames(
97           type_graph, static_cast<FunctionIR *>(lm));
98       break;
99     case GlobalVarKind:
100       ReplaceGlobalVarTypeIdsWithTypeNames(
101           type_graph, static_cast<GlobalVarIR *>(lm));
102       break;
103     case RecordTypeKind:
104       ReplaceRecordTypeIRTypeIdsWithTypeNames(
105           type_graph, static_cast<RecordTypeIR *>(lm));
106       break;
107     case EnumTypeKind:
108       ReplaceEnumTypeIRTypeIdsWithTypeNames(
109           type_graph, static_cast<EnumTypeIR *>(lm));
110       break;
111     default:
112       // This method should not be called on any other LinkableMessage
113       assert(0);
114   }
115 }
116 
UnwindTypeStack()117 std::string AbiDiffHelper::UnwindTypeStack() {
118   return android::base::Join(type_stack_, "-> ");
119 }
120 
CompareEnumFields(const std::vector<EnumFieldIR> & old_fields,const std::vector<EnumFieldIR> & new_fields,EnumTypeDiffIR * enum_type_diff_ir)121 void AbiDiffHelper::CompareEnumFields(
122     const std::vector<EnumFieldIR> &old_fields,
123     const std::vector<EnumFieldIR> &new_fields,
124     EnumTypeDiffIR *enum_type_diff_ir) {
125   AbiElementMap<const EnumFieldIR *> old_fields_map;
126   AbiElementMap<const EnumFieldIR *> new_fields_map;
127   utils::AddToMap(&old_fields_map, old_fields,
128                   [](const EnumFieldIR *f) {return f->GetName();},
129                   [](const EnumFieldIR *f) {return f;});
130 
131   utils::AddToMap(&new_fields_map, new_fields,
132                   [](const EnumFieldIR *f) {return f->GetName();},
133                   [](const EnumFieldIR *f) {return f;});
134 
135   std::vector<const EnumFieldIR *> removed_fields =
136       utils::FindRemovedElements(old_fields_map, new_fields_map);
137 
138   std::vector<const EnumFieldIR *> added_fields =
139       utils::FindRemovedElements(new_fields_map, old_fields_map);
140 
141   enum_type_diff_ir->SetFieldsAdded(std::move(added_fields));
142 
143   enum_type_diff_ir->SetFieldsRemoved(std::move(removed_fields));
144 
145   std::vector<std::pair<const EnumFieldIR *,
146                         const EnumFieldIR *>> cf =
147       utils::FindCommonElements(old_fields_map, new_fields_map);
148   std::vector<EnumFieldDiffIR> enum_field_diffs;
149   for (auto &&common_fields : cf) {
150     if (common_fields.first->GetSignedValue() !=
151         common_fields.second->GetSignedValue()) {
152       EnumFieldDiffIR enum_field_diff_ir(common_fields.first,
153                                          common_fields.second);
154       enum_field_diffs.emplace_back(std::move(enum_field_diff_ir));
155     }
156   }
157   enum_type_diff_ir->SetFieldsDiff(std::move(enum_field_diffs));
158 }
159 
CompareEnumTypes(const EnumTypeIR * old_type,const EnumTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)160 DiffStatus AbiDiffHelper::CompareEnumTypes(const EnumTypeIR *old_type,
161                                            const EnumTypeIR *new_type,
162                                            DiffMessageIR::DiffKind diff_kind) {
163   if (old_type->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
164     return DiffStatus::kDirectDiff;
165   }
166   auto enum_type_diff_ir = std::make_unique<EnumTypeDiffIR>();
167   enum_type_diff_ir->SetName(old_type->GetName());
168   enum_type_diff_ir->SetLinkerSetKey(old_type->GetLinkerSetKey());
169   const std::string &old_underlying_type =
170       ConvertTypeIdToString(old_types_, old_type->GetUnderlyingType());
171   const std::string &new_underlying_type =
172       ConvertTypeIdToString(new_types_, new_type->GetUnderlyingType());
173   if (old_underlying_type != new_underlying_type) {
174     enum_type_diff_ir->SetUnderlyingTypeDiff(
175         std::make_unique<std::pair<std::string, std::string>>(
176             old_underlying_type, new_underlying_type));
177   }
178   CompareEnumFields(old_type->GetFields(), new_type->GetFields(),
179                     enum_type_diff_ir.get());
180   if ((enum_type_diff_ir->IsExtended() ||
181        enum_type_diff_ir->IsIncompatible()) &&
182       (ir_diff_dumper_ &&
183        !ir_diff_dumper_->AddDiffMessageIR(enum_type_diff_ir.get(),
184                                           UnwindTypeStack(), diff_kind))) {
185     llvm::errs() << "AddDiffMessage on EnumTypeDiffIR failed\n";
186     ::exit(1);
187   }
188   return DiffStatus::kNoDiff;
189 }
190 
RemoveThunkInfoFromMangledName(const std::string & name)191 static std::string RemoveThunkInfoFromMangledName(const std::string &name) {
192   if (name.find("_ZTv") != 0 && name.find("_ZTh") != 0 &&
193       name.find("_ZTc") != 0) {
194     return name;
195   }
196   size_t base_name_pos = name.find("N");
197   if (base_name_pos == std::string::npos) {
198     return name;
199   }
200   return "_Z" + name.substr(base_name_pos);
201 }
202 
CompareVTableComponents(const VTableComponentIR & old_component,const VTableComponentIR & new_component)203 static bool CompareVTableComponents(const VTableComponentIR &old_component,
204                                     const VTableComponentIR &new_component) {
205   // Vtable components in prebuilts/abi-dumps/vndk/28 don't have thunk info.
206   if (old_component.GetName() != new_component.GetName()) {
207     if (RemoveThunkInfoFromMangledName(old_component.GetName()) ==
208         RemoveThunkInfoFromMangledName(new_component.GetName())) {
209       llvm::errs() << "WARNING: Ignore difference between "
210                    << old_component.GetName() << " and "
211                    << new_component.GetName() << "\n";
212     } else {
213       return false;
214     }
215   }
216   return old_component.GetValue() == new_component.GetValue() &&
217          old_component.GetKind() == new_component.GetKind();
218 }
219 
CompareVTables(const std::vector<VTableComponentIR> & old_components,const std::vector<VTableComponentIR> & new_components)220 static bool CompareVTables(
221     const std::vector<VTableComponentIR> &old_components,
222     const std::vector<VTableComponentIR> &new_components) {
223   if (old_components.size() != new_components.size()) {
224     return false;
225   }
226   for (size_t i = 0; i < old_components.size(); i++) {
227     if (!CompareVTableComponents(old_components[i], new_components[i])) {
228       return false;
229     }
230   }
231   return true;
232 }
233 
IsVOffset(VTableComponentIR::Kind kind)234 static inline bool IsVOffset(VTableComponentIR::Kind kind) {
235   return kind == VTableComponentIR::VBaseOffset ||
236          kind == VTableComponentIR::VCallOffset;
237 }
238 
IsFunctionPointer(VTableComponentIR::Kind kind)239 static inline bool IsFunctionPointer(VTableComponentIR::Kind kind) {
240   return kind == VTableComponentIR::FunctionPointer ||
241          kind == VTableComponentIR::CompleteDtorPointer ||
242          kind == VTableComponentIR::DeletingDtorPointer;
243 }
244 
245 // A Vtable consists of one or more sub-vtables. Each sub-vtable is a sequence
246 // of components in the following order:
247 //   Zero or more VCallOffset or VBaseOffset.
248 //   One OffsetToTop.
249 //   One RTTI.
250 //   Zero or more FunctionPointer, CompleteDtorPointer, or DeletingDtorPointer.
251 //
252 // An object's vtable pointer points to the next component of the RTTI
253 // component. Hence, new components can be appended or prepended to sub-vtables
254 // without breaking compatibility.
IsVTableExtended(const std::vector<VTableComponentIR> & old_components,const std::vector<VTableComponentIR> & new_components)255 static bool IsVTableExtended(
256     const std::vector<VTableComponentIR> &old_components,
257     const std::vector<VTableComponentIR> &new_components) {
258   const auto old_end = old_components.end();
259   const auto new_end = new_components.end();
260   auto old_it = old_components.begin();
261   auto new_it = new_components.begin();
262   bool is_extended = false;
263   while (old_it != old_end) {
264     const auto old_begin = old_it;
265     const auto new_begin = new_it;
266     // Iterate VCallOffset and VBaseOffset.
267     while (old_it != old_end && IsVOffset(old_it->GetKind())) {
268       old_it++;
269     }
270     while (new_it != new_end && IsVOffset(new_it->GetKind())) {
271       new_it++;
272     }
273     // Compare VCallOffset and VBaseOffset.
274     auto old_back_it = old_it;
275     auto new_back_it = new_it;
276     while (old_back_it != old_begin) {
277       if (new_back_it == new_begin) {
278         return false;
279       }
280       old_back_it--;
281       new_back_it--;
282       if (old_back_it->GetKind() != new_back_it->GetKind()) {
283         return false;
284       }
285     }
286     // The new sub-vtable has additional VOffsets at the beginning.
287     if (new_back_it != new_begin) {
288       is_extended = true;
289     }
290     // Compare OffsetToTop.
291     if (old_it == old_end || new_it == new_end ||
292         old_it->GetKind() != VTableComponentIR::OffsetToTop ||
293         new_it->GetKind() != VTableComponentIR::OffsetToTop) {
294       return false;
295     }
296     old_it++;
297     new_it++;
298     // Compare RTTI.
299     if (old_it == old_end || new_it == new_end ||
300         old_it->GetKind() != VTableComponentIR::RTTI ||
301         new_it->GetKind() != VTableComponentIR::RTTI ||
302         old_it->GetName() != new_it->GetName()) {
303       return false;
304     }
305     old_it++;
306     new_it++;
307     // Compare function pointers.
308     while (old_it != old_end && IsFunctionPointer(old_it->GetKind())) {
309       if (new_it == new_end || old_it->GetKind() != new_it->GetKind() ||
310           old_it->GetName() != new_it->GetName()) {
311         return false;
312       }
313       old_it++;
314       new_it++;
315     }
316     // The new sub-vtable has additional function pointers at the end.
317     while (new_it != new_end && IsFunctionPointer(new_it->GetKind())) {
318       is_extended = true;
319       new_it++;
320     }
321   }
322   return new_it == new_end ? is_extended : false;
323 }
324 
AreOpaqueTypesEqual(const std::string & old_type_id,const std::string & new_type_id) const325 bool AbiDiffHelper::AreOpaqueTypesEqual(const std::string &old_type_id,
326                                         const std::string &new_type_id) const {
327   // b/253095767: In T, some dump files contain opaque types whose IDs end with
328   // "#ODR:" and the source paths. This function removes the suffixes before
329   // comparing the type IDs.
330   if (!diff_policy_options_.consider_opaque_types_different_ ||
331       ExtractMultiDefinitionTypeId(old_type_id) ==
332           ExtractMultiDefinitionTypeId(new_type_id)) {
333     return true;
334   }
335   // __va_list is an opaque type defined by the compiler. ARM ABI requires
336   // __va_list to be in std namespace. Its mangled name is _ZTISt9__va_list, but
337   // some versions of clang produce _ZTI9__va_list. The names are equivalent.
338   static const std::unordered_set<std::string> va_list_names{
339       "_ZTI9__va_list", "_ZTISt9__va_list"};
340   return va_list_names.count(old_type_id) && va_list_names.count(new_type_id);
341 }
342 
CompareSizeAndAlignment(const TypeIR * old_type,const TypeIR * new_type)343 static bool CompareSizeAndAlignment(const TypeIR *old_type,
344                                     const TypeIR *new_type) {
345   return old_type->GetSize() == new_type->GetSize() &&
346       old_type->GetAlignment() == new_type->GetAlignment();
347 }
348 
CompareAccess(AccessSpecifierIR old_access,AccessSpecifierIR new_access)349 DiffStatus AbiDiffHelper::CompareAccess(AccessSpecifierIR old_access,
350                                         AccessSpecifierIR new_access) {
351   if (old_access == new_access) {
352     return DiffStatus::kNoDiff;
353   }
354   if (old_access > new_access) {
355     return DiffStatus::kDirectExt;
356   }
357   return DiffStatus::kDirectDiff;
358 }
359 
360 // This function returns a map from field names to RecordFieldIR.
361 // It appends anonymous fields to anonymous_fields.
BuildRecordFieldNameMap(const std::vector<RecordFieldIR> & fields,std::vector<const RecordFieldIR * > & anonymous_fields)362 static AbiElementMap<const RecordFieldIR *> BuildRecordFieldNameMap(
363     const std::vector<RecordFieldIR> &fields,
364     std::vector<const RecordFieldIR *> &anonymous_fields) {
365   AbiElementMap<const RecordFieldIR *> field_map;
366   for (const RecordFieldIR &field : fields) {
367     const std::string &name = field.GetName();
368     if (name.empty()) {
369       anonymous_fields.emplace_back(&field);
370     } else {
371       field_map.emplace(name, &field);
372     }
373   }
374   return field_map;
375 }
376 
CompareCommonRecordFields(const RecordFieldIR * old_field,const RecordFieldIR * new_field,DiffMessageIR::DiffKind diff_kind)377 DiffStatus AbiDiffHelper::CompareCommonRecordFields(
378     const RecordFieldIR *old_field, const RecordFieldIR *new_field,
379     DiffMessageIR::DiffKind diff_kind) {
380   DiffStatus field_diff_status =
381       CompareAndDumpTypeDiff(old_field->GetReferencedType(),
382                              new_field->GetReferencedType(), diff_kind);
383   // CompareAndDumpTypeDiff should not return kDirectExt.
384   // In case it happens, report an incompatible diff for review.
385   if (field_diff_status.IsExtension() ||
386       old_field->GetOffset() != new_field->GetOffset() ||
387       old_field->IsBitField() != new_field->IsBitField() ||
388       old_field->GetBitWidth() != new_field->GetBitWidth()) {
389     field_diff_status.CombineWith(DiffStatus::kDirectDiff);
390   }
391   field_diff_status.CombineWith(
392       CompareAccess(old_field->GetAccess(), new_field->GetAccess()));
393   return field_diff_status;
394 }
395 
396 // FilterOutRenamedRecordFields calls this function to compare record fields in
397 // two dumps.
398 // If this function returns 0, the fields may be compatible.
399 // If it returns -1 or 1, the fields must be incompatible.
CompareRenamedRecordFields(const RecordFieldIR * old_field,const RecordFieldIR * new_field)400 static int CompareRenamedRecordFields(const RecordFieldIR *old_field,
401                                       const RecordFieldIR *new_field) {
402   if (old_field->GetOffset() != new_field->GetOffset()) {
403     return old_field->GetOffset() < new_field->GetOffset() ? -1 : 1;
404   }
405   if (old_field->IsBitField() != new_field->IsBitField()) {
406     return old_field->IsBitField() < new_field->IsBitField() ? -1 : 1;
407   }
408   if (old_field->GetBitWidth() != new_field->GetBitWidth()) {
409     return old_field->GetBitWidth() < new_field->GetBitWidth() ? -1 : 1;
410   }
411   // Skip GetReferencedType because the same type in old and new dumps may have
412   // different IDs, especially in the cases of anonymous types and multiple
413   // definitions.
414   return 0;
415 }
416 
417 // This function filters out the pairs of old and new fields that meet the
418 // following conditions:
419 //   The old field's (offset, bit width, type) is unique in old_fields.
420 //   The new field's (offset, bit width, type) is unique in new_fields.
421 //   The two fields have compatible attributes except the name.
422 //
423 // This function returns either kNoDiff or kIndirectDiff. It is the status of
424 // the field pairs that are filtered out.
FilterOutRenamedRecordFields(DiffMessageIR::DiffKind diff_kind,std::vector<const RecordFieldIR * > & old_fields,std::vector<const RecordFieldIR * > & new_fields)425 DiffStatus AbiDiffHelper::FilterOutRenamedRecordFields(
426     DiffMessageIR::DiffKind diff_kind,
427     std::vector<const RecordFieldIR *> &old_fields,
428     std::vector<const RecordFieldIR *> &new_fields) {
429   DiffStatus diff_status = DiffStatus::kNoDiff;
430   const auto old_end = old_fields.end();
431   const auto new_end = new_fields.end();
432   // Sort fields by (offset, bit width, type).
433   auto is_less = [](const RecordFieldIR *first, const RecordFieldIR *second) {
434     int result = CompareRenamedRecordFields(first, second);
435     return result != 0
436                ? result < 0
437                : first->GetReferencedType() < second->GetReferencedType();
438   };
439   std::sort(old_fields.begin(), old_end, is_less);
440   std::sort(new_fields.begin(), new_end, is_less);
441 
442   std::vector<const RecordFieldIR *> out_old_fields;
443   std::vector<const RecordFieldIR *> out_new_fields;
444   auto old_it = old_fields.begin();
445   auto new_it = new_fields.begin();
446   while (old_it != old_end && new_it != new_end) {
447     int old_new_cmp = CompareRenamedRecordFields(*old_it, *new_it);
448     auto next_old_it = std::next(old_it);
449     while (next_old_it != old_end && !is_less(*old_it, *next_old_it)) {
450       next_old_it++;
451     }
452     if (old_new_cmp < 0 || next_old_it - old_it > 1) {
453       out_old_fields.insert(out_old_fields.end(), old_it, next_old_it);
454       old_it = next_old_it;
455       continue;
456     }
457 
458     auto next_new_it = std::next(new_it);
459     while (next_new_it != new_end && !is_less(*new_it, *next_new_it)) {
460       next_new_it++;
461     }
462     if (old_new_cmp > 0 || next_new_it - new_it > 1) {
463       out_new_fields.insert(out_new_fields.end(), new_it, next_new_it);
464       new_it = next_new_it;
465       continue;
466     }
467 
468     DiffStatus field_diff_status =
469         CompareCommonRecordFields(*old_it, *new_it, diff_kind);
470     if (field_diff_status.IsDirectDiff()) {
471       out_old_fields.emplace_back(*old_it);
472       out_new_fields.emplace_back(*new_it);
473     } else {
474       diff_status.CombineWith(field_diff_status);
475     }
476     old_it = next_old_it;
477     new_it = next_new_it;
478   }
479   out_old_fields.insert(out_old_fields.end(), old_it, old_end);
480   out_new_fields.insert(out_new_fields.end(), new_it, new_end);
481 
482   old_fields = std::move(out_old_fields);
483   new_fields = std::move(out_new_fields);
484   return diff_status;
485 }
486 
CompareRecordFields(const std::vector<RecordFieldIR> & old_fields,const std::vector<RecordFieldIR> & new_fields,DiffMessageIR::DiffKind diff_kind)487 RecordFieldDiffResult AbiDiffHelper::CompareRecordFields(
488     const std::vector<RecordFieldIR> &old_fields,
489     const std::vector<RecordFieldIR> &new_fields,
490     DiffMessageIR::DiffKind diff_kind) {
491   RecordFieldDiffResult result;
492   DiffStatus &diff_status = result.status;
493   diff_status = DiffStatus::kNoDiff;
494   AbiElementMap<const RecordFieldIR *> old_fields_map =
495       BuildRecordFieldNameMap(old_fields, result.removed_fields);
496   AbiElementMap<const RecordFieldIR *> new_fields_map =
497       BuildRecordFieldNameMap(new_fields, result.added_fields);
498 
499   // Compare the anonymous fields and the fields whose names are not present in
500   // both records.
501   utils::InsertAll(result.removed_fields,
502                    utils::FindRemovedElements(old_fields_map, new_fields_map));
503   utils::InsertAll(result.added_fields,
504                    utils::FindRemovedElements(new_fields_map, old_fields_map));
505   diff_status.CombineWith(FilterOutRenamedRecordFields(
506       diff_kind, result.removed_fields, result.added_fields));
507   if (result.removed_fields.size() != 0) {
508     diff_status.CombineWith(DiffStatus::kDirectDiff);
509   }
510   if (result.added_fields.size() != 0) {
511     diff_status.CombineWith(DiffStatus::kDirectExt);
512   }
513   // Compare the fields whose names are present in both records.
514   std::vector<std::pair<const RecordFieldIR *, const RecordFieldIR *>> cf =
515       utils::FindCommonElements(old_fields_map, new_fields_map);
516   for (auto &&common_fields : cf) {
517     DiffStatus field_diff_status = CompareCommonRecordFields(
518         common_fields.first, common_fields.second, diff_kind);
519     diff_status.CombineWith(field_diff_status);
520     if (field_diff_status.IsDirectDiff()) {
521       result.diffed_fields.emplace_back(common_fields.first,
522                                         common_fields.second);
523     }
524   }
525   return result;
526 }
527 
CompareBaseSpecifiers(const std::vector<CXXBaseSpecifierIR> & old_base_specifiers,const std::vector<CXXBaseSpecifierIR> & new_base_specifiers,DiffMessageIR::DiffKind diff_kind)528 bool AbiDiffHelper::CompareBaseSpecifiers(
529     const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
530     const std::vector<CXXBaseSpecifierIR> &new_base_specifiers,
531     DiffMessageIR::DiffKind diff_kind) {
532   if (old_base_specifiers.size() != new_base_specifiers.size()) {
533     return false;
534   }
535   int i = 0;
536   while (i < old_base_specifiers.size()) {
537     if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(),
538                                new_base_specifiers.at(i).GetReferencedType(),
539                                diff_kind)
540             .IsDirectDiff() ||
541         (old_base_specifiers.at(i).GetAccess() !=
542          new_base_specifiers.at(i).GetAccess())) {
543       return false;
544     }
545     i++;
546   }
547   return true;
548 }
549 
CompareTemplateInfo(const std::vector<TemplateElementIR> & old_template_elements,const std::vector<TemplateElementIR> & new_template_elements,DiffMessageIR::DiffKind diff_kind)550 DiffStatus AbiDiffHelper::CompareTemplateInfo(
551     const std::vector<TemplateElementIR> &old_template_elements,
552     const std::vector<TemplateElementIR> &new_template_elements,
553     DiffMessageIR::DiffKind diff_kind) {
554   uint32_t old_template_size = old_template_elements.size();
555   uint32_t i = 0;
556   if (old_template_size != new_template_elements.size()) {
557     return DiffStatus::kDirectDiff;
558   }
559   DiffStatus final_diff_status = DiffStatus::kNoDiff;
560   while (i < old_template_size) {
561     const TemplateElementIR &old_template_element =
562         old_template_elements[i];
563     const TemplateElementIR &new_template_element =
564         new_template_elements[i];
565     auto template_element_diff = CompareAndDumpTypeDiff(
566         old_template_element.GetReferencedType(),
567         new_template_element.GetReferencedType(), diff_kind);
568     if (template_element_diff.HasDiff()) {
569       final_diff_status.CombineWith(template_element_diff);
570     }
571     i++;
572   }
573   return final_diff_status;
574 }
575 
576 template <typename DiffContainer, typename T>
ConvertToDiffContainerVector(std::vector<std::pair<T,T>> & nc_vector)577 static std::vector<DiffContainer> ConvertToDiffContainerVector(
578     std::vector<std::pair<T, T>> &nc_vector) {
579   std::vector<DiffContainer> cptr_vec;
580   for (auto &e : nc_vector) {
581     cptr_vec.emplace_back(&e.first, &e.second);
582   }
583   return cptr_vec;
584 }
585 
586 template <typename T>
ConvertToConstPtrVector(std::vector<T> & nc_vector)587 static std::vector<const T*> ConvertToConstPtrVector(
588     std::vector<T> &nc_vector) {
589   std::vector<const T*> cptr_vec;
590   for (auto &e : nc_vector) {
591     cptr_vec.emplace_back(&e);
592   }
593   return cptr_vec;
594 }
595 
FixupRemovedFieldTypeIds(const std::vector<const RecordFieldIR * > & removed_fields,const AbiElementMap<const TypeIR * > & old_types)596 static std::vector<RecordFieldIR> FixupRemovedFieldTypeIds(
597     const std::vector<const RecordFieldIR *> &removed_fields,
598     const AbiElementMap<const TypeIR *> &old_types) {
599   std::vector<RecordFieldIR> removed_fields_dup;
600   for (auto &removed_field : removed_fields) {
601     removed_fields_dup.emplace_back(*removed_field);
602     RecordFieldIR &it = removed_fields_dup[removed_fields_dup.size() -1];
603     it.SetReferencedType(
604         ConvertTypeIdToString(old_types, it.GetReferencedType()));
605   }
606   return removed_fields_dup;
607 }
608 
609 std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
FixupDiffedFieldTypeIds(const std::vector<RecordFieldDiffIR> & field_diffs)610 AbiDiffHelper::FixupDiffedFieldTypeIds(
611     const std::vector<RecordFieldDiffIR> &field_diffs) {
612   std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
613       diffed_fields_dup;
614   for (auto &field_diff : field_diffs) {
615     diffed_fields_dup.emplace_back(*(field_diff.old_field_),
616                                    *(field_diff.new_field_));
617     auto &it = diffed_fields_dup[diffed_fields_dup.size() - 1];
618     RecordFieldIR &old_field = it.first;
619     RecordFieldIR &new_field = it.second;
620     old_field.SetReferencedType(
621         ConvertTypeIdToString(old_types_, old_field.GetReferencedType()));
622     new_field.SetReferencedType(
623         ConvertTypeIdToString(new_types_, new_field.GetReferencedType()));
624   }
625   return diffed_fields_dup;
626 }
627 
CompareFunctionTypes(const CFunctionLikeIR * old_type,const CFunctionLikeIR * new_type,DiffMessageIR::DiffKind diff_kind)628 DiffStatus AbiDiffHelper::CompareFunctionTypes(
629     const CFunctionLikeIR *old_type, const CFunctionLikeIR *new_type,
630     DiffMessageIR::DiffKind diff_kind) {
631   DiffStatus status = CompareFunctionParameters(
632       old_type->GetParameters(), new_type->GetParameters(), diff_kind);
633   status.CombineWith(CompareReturnTypes(old_type->GetReturnType(),
634                                         new_type->GetReturnType(), diff_kind));
635   return status;
636 }
637 
CompareRecordTypes(const RecordTypeIR * old_type,const RecordTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)638 DiffStatus AbiDiffHelper::CompareRecordTypes(
639     const RecordTypeIR *old_type, const RecordTypeIR *new_type,
640     DiffMessageIR::DiffKind diff_kind) {
641   auto record_type_diff_ir = std::make_unique<RecordTypeDiffIR>();
642   // Compare names.
643   if (!old_type->IsAnonymous() && !new_type->IsAnonymous() &&
644       old_type->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
645     // Do not dump anything since the record types themselves are fundamentally
646     // different.
647     return DiffStatus::kDirectDiff;
648   }
649   DiffStatus final_diff_status = DiffStatus::kNoDiff;
650   record_type_diff_ir->SetName(old_type->GetName());
651   record_type_diff_ir->SetLinkerSetKey(old_type->GetLinkerSetKey());
652 
653   DiffStatus access_diff_status =
654       CompareAccess(old_type->GetAccess(), new_type->GetAccess());
655   final_diff_status.CombineWith(access_diff_status);
656   if (access_diff_status.HasDiff()) {
657     record_type_diff_ir->SetAccessDiff(
658         std::make_unique<AccessSpecifierDiffIR>(
659             old_type->GetAccess(), new_type->GetAccess()));
660   }
661 
662   if (!CompareSizeAndAlignment(old_type, new_type)) {
663     if (old_type->GetSize() < new_type->GetSize() &&
664         old_type->GetAlignment() == new_type->GetAlignment()) {
665       final_diff_status.CombineWith(DiffStatus::kDirectExt);
666     } else {
667       final_diff_status.CombineWith(DiffStatus::kDirectDiff);
668     }
669     record_type_diff_ir->SetTypeDiff(
670         std::make_unique<TypeDiffIR>(
671             std::make_pair(old_type->GetSize(), new_type->GetSize()),
672             std::make_pair(old_type->GetAlignment(),
673                            new_type->GetAlignment())));
674   }
675 
676   const std::vector<VTableComponentIR> &old_vtable =
677       old_type->GetVTableLayout().GetVTableComponents();
678   const std::vector<VTableComponentIR> &new_vtable =
679       new_type->GetVTableLayout().GetVTableComponents();
680   if (!CompareVTables(old_vtable, new_vtable)) {
681     if (IsVTableExtended(old_vtable, new_vtable)) {
682       final_diff_status.CombineWith(DiffStatus::kDirectExt);
683     } else {
684       final_diff_status.CombineWith(DiffStatus::kDirectDiff);
685     }
686     record_type_diff_ir->SetVTableLayoutDiff(
687         std::make_unique<VTableLayoutDiffIR>(
688             old_type->GetVTableLayout(), new_type->GetVTableLayout()));
689   }
690 
691   auto &old_fields_dup = old_type->GetFields();
692   auto &new_fields_dup = new_type->GetFields();
693   RecordFieldDiffResult field_status_and_diffs =
694       CompareRecordFields(old_fields_dup, new_fields_dup, diff_kind);
695   final_diff_status.CombineWith(field_status_and_diffs.status);
696 
697   std::vector<CXXBaseSpecifierIR> old_bases = old_type->GetBases();
698   std::vector<CXXBaseSpecifierIR> new_bases = new_type->GetBases();
699   if (!CompareBaseSpecifiers(old_bases, new_bases, diff_kind) &&
700       ir_diff_dumper_) {
701     final_diff_status.CombineWith(DiffStatus::kDirectDiff);
702     ReplaceReferencesOtherTypeIdWithName(old_types_, old_bases);
703     ReplaceReferencesOtherTypeIdWithName(new_types_, new_bases);
704     record_type_diff_ir->SetBaseSpecifierDiffs(
705         std::make_unique<CXXBaseSpecifierDiffIR>(old_bases, new_bases));
706   }
707   if (ir_diff_dumper_) {
708     // Make copies of the fields removed and diffed, since we have to change
709     // type ids -> type strings.
710     std::vector<std::pair<RecordFieldIR, RecordFieldIR>> field_diff_dups =
711         FixupDiffedFieldTypeIds(field_status_and_diffs.diffed_fields);
712     std::vector<RecordFieldDiffIR> field_diffs_fixed =
713         ConvertToDiffContainerVector<RecordFieldDiffIR,
714                                      RecordFieldIR>(field_diff_dups);
715 
716     std::vector<RecordFieldIR> field_removed_dups = FixupRemovedFieldTypeIds(
717         field_status_and_diffs.removed_fields, old_types_);
718     std::vector<const RecordFieldIR *> fields_removed_fixed =
719         ConvertToConstPtrVector(field_removed_dups);
720 
721     std::vector<RecordFieldIR> field_added_dups = FixupRemovedFieldTypeIds(
722         field_status_and_diffs.added_fields, new_types_);
723     std::vector<const RecordFieldIR *> fields_added_fixed =
724         ConvertToConstPtrVector(field_added_dups);
725 
726     record_type_diff_ir->SetFieldDiffs(std::move(field_diffs_fixed));
727     record_type_diff_ir->SetFieldsRemoved(std::move(fields_removed_fixed));
728     record_type_diff_ir->SetFieldsAdded(std::move(fields_added_fixed));
729     record_type_diff_ir->SetExtended(final_diff_status.IsExtension());
730 
731     if (final_diff_status.IsDirectDiff() &&
732         !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
733                                            UnwindTypeStack(), diff_kind)) {
734       llvm::errs() << "AddDiffMessage on record type failed\n";
735       ::exit(1);
736     }
737   }
738 
739   final_diff_status.CombineWith(
740       CompareTemplateInfo(old_type->GetTemplateElements(),
741                           new_type->GetTemplateElements(), diff_kind));
742 
743   return (final_diff_status.HasDiff() ? DiffStatus::kIndirectDiff
744                                       : DiffStatus::kNoDiff);
745 }
746 
CompareLvalueReferenceTypes(const LvalueReferenceTypeIR * old_type,const LvalueReferenceTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)747 DiffStatus AbiDiffHelper::CompareLvalueReferenceTypes(
748     const LvalueReferenceTypeIR *old_type,
749     const LvalueReferenceTypeIR *new_type, DiffMessageIR::DiffKind diff_kind) {
750   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
751                                 new_type->GetReferencedType(), diff_kind);
752 }
753 
CompareRvalueReferenceTypes(const RvalueReferenceTypeIR * old_type,const RvalueReferenceTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)754 DiffStatus AbiDiffHelper::CompareRvalueReferenceTypes(
755     const RvalueReferenceTypeIR *old_type,
756     const RvalueReferenceTypeIR *new_type, DiffMessageIR::DiffKind diff_kind) {
757   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
758                                 new_type->GetReferencedType(), diff_kind);
759 }
760 
CompareQualifiedTypes(const QualifiedTypeIR * old_type,const QualifiedTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)761 DiffStatus AbiDiffHelper::CompareQualifiedTypes(
762     const QualifiedTypeIR *old_type, const QualifiedTypeIR *new_type,
763     DiffMessageIR::DiffKind diff_kind) {
764   // If all the qualifiers are not the same, return direct_diff, else
765   // recursively compare the unqualified types.
766   if (old_type->IsConst() != new_type->IsConst() ||
767       old_type->IsVolatile() != new_type->IsVolatile() ||
768       old_type->IsRestricted() != new_type->IsRestricted()) {
769     return DiffStatus::kDirectDiff;
770   }
771   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
772                                 new_type->GetReferencedType(), diff_kind);
773 }
774 
CompareArrayTypes(const ArrayTypeIR * old_type,const ArrayTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)775 DiffStatus AbiDiffHelper::CompareArrayTypes(const ArrayTypeIR *old_type,
776                                             const ArrayTypeIR *new_type,
777                                             DiffMessageIR::DiffKind diff_kind) {
778   if (!CompareSizeAndAlignment(old_type, new_type) ||
779       old_type->IsOfUnknownBound() != new_type->IsOfUnknownBound()) {
780     return DiffStatus::kDirectDiff;
781   }
782   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
783                                 new_type->GetReferencedType(), diff_kind);
784 }
785 
ComparePointerTypes(const PointerTypeIR * old_type,const PointerTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)786 DiffStatus AbiDiffHelper::ComparePointerTypes(
787     const PointerTypeIR *old_type, const PointerTypeIR *new_type,
788     DiffMessageIR::DiffKind diff_kind) {
789   // The following need to be the same for two pointer types to be considered
790   // equivalent:
791   // 1) Number of pointer indirections are the same.
792   // 2) The ultimate pointee is the same.
793   assert(CompareSizeAndAlignment(old_type, new_type));
794   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
795                                 new_type->GetReferencedType(), diff_kind);
796 }
797 
CompareBuiltinTypes(const BuiltinTypeIR * old_type,const BuiltinTypeIR * new_type)798 DiffStatus AbiDiffHelper::CompareBuiltinTypes(
799     const BuiltinTypeIR *old_type,
800     const BuiltinTypeIR *new_type) {
801   // If the size, alignment and is_unsigned are the same, return no_diff
802   // else return direct_diff.
803   if (!CompareSizeAndAlignment(old_type, new_type) ||
804       old_type->IsUnsigned() != new_type->IsUnsigned() ||
805       old_type->IsIntegralType() != new_type->IsIntegralType()) {
806     return DiffStatus::kDirectDiff;
807   }
808   return DiffStatus::kNoDiff;
809 }
810 
CompareFunctionParameters(const std::vector<ParamIR> & old_parameters,const std::vector<ParamIR> & new_parameters,DiffMessageIR::DiffKind diff_kind)811 DiffStatus AbiDiffHelper::CompareFunctionParameters(
812     const std::vector<ParamIR> &old_parameters,
813     const std::vector<ParamIR> &new_parameters,
814     DiffMessageIR::DiffKind diff_kind) {
815   size_t old_parameters_size = old_parameters.size();
816   if (old_parameters_size != new_parameters.size()) {
817     return DiffStatus::kDirectDiff;
818   }
819   DiffStatus result = DiffStatus::kNoDiff;
820   for (uint64_t i = 0; i < old_parameters_size; i++) {
821     const ParamIR &old_parameter = old_parameters.at(i);
822     const ParamIR &new_parameter = new_parameters.at(i);
823     result.CombineWith(CompareParameterTypes(old_parameter.GetReferencedType(),
824                                              new_parameter.GetReferencedType(),
825                                              diff_kind));
826     if (old_parameter.GetIsDefault() != new_parameter.GetIsDefault()) {
827       result.CombineWith(DiffStatus::kDirectDiff);
828     }
829   }
830   return result;
831 }
832 
FindTypeById(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)833 static const TypeIR *FindTypeById(
834     const AbiElementMap<const TypeIR *> &type_graph,
835     const std::string &type_id) {
836   auto it = type_graph.find(type_id);
837   return it == type_graph.end() ? nullptr : it->second;
838 }
839 
840 struct Qualifiers {
841   bool is_const = false;
842   bool is_restricted = false;
843   bool is_volatile = false;
844 
operator ==header_checker::repr::Qualifiers845   bool operator==(const Qualifiers &other) const {
846     return (is_const == other.is_const &&
847             is_restricted == other.is_restricted &&
848             is_volatile == other.is_volatile);
849   }
850 
operator !=header_checker::repr::Qualifiers851   bool operator!=(const Qualifiers &other) const { return !(*this == other); }
852 };
853 
854 // This function returns the qualifiers and sets type_id to the unqalified or
855 // opaque type.
ResolveQualifiers(const AbiElementMap<const TypeIR * > & types,std::string & type_id)856 static Qualifiers ResolveQualifiers(const AbiElementMap<const TypeIR *> &types,
857                                     std::string &type_id) {
858   Qualifiers qual;
859   while (true) {
860     const TypeIR *type_ir = FindTypeById(types, type_id);
861     if (type_ir == nullptr ||
862         type_ir->GetKind() != LinkableMessageKind::QualifiedTypeKind) {
863       return qual;
864     }
865     const QualifiedTypeIR *qualified_type_ir =
866         static_cast<const QualifiedTypeIR *>(type_ir);
867     qual.is_const |= qualified_type_ir->IsConst();
868     qual.is_restricted |= qualified_type_ir->IsRestricted();
869     qual.is_volatile |= qualified_type_ir->IsVolatile();
870     type_id = qualified_type_ir->GetReferencedType();
871   }
872 }
873 
874 // This function returns whether the old_type can be implicitly casted to
875 // new_type. It resolves qualified pointers and references until it reaches a
876 // type that does not reference other types. It does not compare the final
877 // referenced types.
878 //
879 // If this function returns true, old_type_id and new_type_id are set to the
880 // final referenced types. are_qualifiers_equal represents whether the
881 // qualifiers are exactly the same.
882 //
883 // If this function returns false, old_type_id, new_type_id, and
884 // are_qualifiers_equal do not have valid values.
885 //
886 // This function follows C++ standard to determine whether qualifiers can be
887 // casted. The rules are described in
888 // Section 7.5 Qualification conversions [conv.qual] in C++17 standard
889 // and
890 // https://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions
891 // Additionally, __restrict__ follows the same rules as const and volatile.
ResolveImplicitlyConvertibleQualifiedReferences(const AbiElementMap<const TypeIR * > & old_types,const AbiElementMap<const TypeIR * > & new_types,std::string & old_type_id,std::string & new_type_id,bool & are_qualifiers_equal)892 static bool ResolveImplicitlyConvertibleQualifiedReferences(
893     const AbiElementMap<const TypeIR *> &old_types,
894     const AbiElementMap<const TypeIR *> &new_types, std::string &old_type_id,
895     std::string &new_type_id, bool &are_qualifiers_equal) {
896   are_qualifiers_equal = true;
897   bool is_first_level = true;
898   bool is_const_since_second_level = true;
899   while (true) {
900     // Check qualifiers.
901     const Qualifiers old_qual = ResolveQualifiers(old_types, old_type_id);
902     const Qualifiers new_qual = ResolveQualifiers(new_types, new_type_id);
903     are_qualifiers_equal &= (old_qual == new_qual);
904     if (is_first_level) {
905       is_first_level = false;
906     } else {
907       if ((old_qual.is_const && !new_qual.is_const) ||
908           (old_qual.is_restricted && !new_qual.is_restricted) ||
909           (old_qual.is_volatile && !new_qual.is_volatile)) {
910         return false;
911       }
912       if (!is_const_since_second_level && old_qual != new_qual) {
913         return false;
914       }
915       is_const_since_second_level &= new_qual.is_const;
916     }
917     // Stop if the unqualified types differ or don't reference other types.
918     const TypeIR *old_type = FindTypeById(old_types, old_type_id);
919     const TypeIR *new_type = FindTypeById(new_types, new_type_id);
920     if (old_type == nullptr || new_type == nullptr) {
921       return true;
922     }
923     const LinkableMessageKind kind = old_type->GetKind();
924     if (kind != new_type->GetKind()) {
925       return true;
926     }
927     if (kind != LinkableMessageKind::PointerTypeKind &&
928         kind != LinkableMessageKind::LvalueReferenceTypeKind &&
929         kind != LinkableMessageKind::RvalueReferenceTypeKind) {
930       return true;
931     }
932     // Get the referenced types.
933     old_type_id = old_type->GetReferencedType();
934     new_type_id = new_type->GetReferencedType();
935   }
936 }
937 
CompareParameterTypes(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)938 DiffStatus AbiDiffHelper::CompareParameterTypes(
939     const std::string &old_type_id, const std::string &new_type_id,
940     DiffMessageIR::DiffKind diff_kind) {
941   // Compare size and alignment.
942   const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
943   const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
944   if (old_type_ir != nullptr && new_type_ir != nullptr &&
945       !CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
946     return DiffStatus::kDirectDiff;
947   }
948   // Allow the new parameter to be more qualified than the old parameter.
949   std::string old_referenced_type_id = old_type_id;
950   std::string new_referenced_type_id = new_type_id;
951   bool are_qualifiers_equal;
952   if (!ResolveImplicitlyConvertibleQualifiedReferences(
953           old_types_, new_types_, old_referenced_type_id,
954           new_referenced_type_id, are_qualifiers_equal)) {
955     return DiffStatus::kDirectDiff;
956   }
957   // Compare the unqualified referenced types.
958   DiffStatus result = CompareAndDumpTypeDiff(old_referenced_type_id,
959                                              new_referenced_type_id, diff_kind);
960   if (!are_qualifiers_equal) {
961     result.CombineWith(DiffStatus::kDirectExt);
962   }
963   return result;
964 }
965 
966 // This function is the same as CompareParameterTypes except for the arguments
967 // to ResolveImplicitlyConvertibleQualifiedReferences.
CompareReturnTypes(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)968 DiffStatus AbiDiffHelper::CompareReturnTypes(
969     const std::string &old_type_id, const std::string &new_type_id,
970     DiffMessageIR::DiffKind diff_kind) {
971   // Compare size and alignment.
972   const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
973   const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
974   if (old_type_ir != nullptr && new_type_ir != nullptr &&
975       !CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
976     return DiffStatus::kDirectDiff;
977   }
978   // Allow the new return type to be less qualified than the old return type.
979   std::string old_referenced_type_id = old_type_id;
980   std::string new_referenced_type_id = new_type_id;
981   bool are_qualifiers_equal;
982   if (!ResolveImplicitlyConvertibleQualifiedReferences(
983           new_types_, old_types_, new_referenced_type_id,
984           old_referenced_type_id, are_qualifiers_equal)) {
985     return DiffStatus::kDirectDiff;
986   }
987   // Compare the unqualified referenced types.
988   DiffStatus result = CompareAndDumpTypeDiff(old_referenced_type_id,
989                                              new_referenced_type_id, diff_kind);
990   if (!are_qualifiers_equal) {
991     result.CombineWith(DiffStatus::kDirectExt);
992   }
993   return result;
994 }
995 
CompareAndDumpTypeDiff(const TypeIR * old_type,const TypeIR * new_type,LinkableMessageKind kind,DiffMessageIR::DiffKind diff_kind)996 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
997     const TypeIR *old_type, const TypeIR *new_type, LinkableMessageKind kind,
998     DiffMessageIR::DiffKind diff_kind) {
999   if (ignored_linker_set_keys_.find(new_type->GetLinkerSetKey()) !=
1000       ignored_linker_set_keys_.end()) {
1001     return DiffStatus::kNoDiff;
1002   }
1003 
1004   switch (kind) {
1005     case LinkableMessageKind::BuiltinTypeKind:
1006       return CompareBuiltinTypes(static_cast<const BuiltinTypeIR *>(old_type),
1007                                  static_cast<const BuiltinTypeIR *>(new_type));
1008     case LinkableMessageKind::QualifiedTypeKind:
1009       return CompareQualifiedTypes(
1010           static_cast<const QualifiedTypeIR *>(old_type),
1011           static_cast<const QualifiedTypeIR *>(new_type), diff_kind);
1012     case LinkableMessageKind::ArrayTypeKind:
1013       return CompareArrayTypes(static_cast<const ArrayTypeIR *>(old_type),
1014                                static_cast<const ArrayTypeIR *>(new_type),
1015                                diff_kind);
1016     case LinkableMessageKind::EnumTypeKind:
1017       return CompareEnumTypes(static_cast<const EnumTypeIR *>(old_type),
1018                               static_cast<const EnumTypeIR *>(new_type),
1019                               diff_kind);
1020 
1021     case LinkableMessageKind::LvalueReferenceTypeKind:
1022       return CompareLvalueReferenceTypes(
1023           static_cast<const LvalueReferenceTypeIR *>(old_type),
1024           static_cast<const LvalueReferenceTypeIR *>(new_type), diff_kind);
1025     case LinkableMessageKind::RvalueReferenceTypeKind:
1026       return CompareRvalueReferenceTypes(
1027           static_cast<const RvalueReferenceTypeIR *>(old_type),
1028           static_cast<const RvalueReferenceTypeIR *>(new_type), diff_kind);
1029     case LinkableMessageKind::PointerTypeKind:
1030       return ComparePointerTypes(static_cast<const PointerTypeIR *>(old_type),
1031                                  static_cast<const PointerTypeIR *>(new_type),
1032                                  diff_kind);
1033 
1034     case LinkableMessageKind::RecordTypeKind:
1035       return CompareRecordTypes(static_cast<const RecordTypeIR *>(old_type),
1036                                 static_cast<const RecordTypeIR *>(new_type),
1037                                 diff_kind);
1038 
1039     case LinkableMessageKind::FunctionTypeKind: {
1040       DiffStatus result = CompareFunctionTypes(
1041           static_cast<const FunctionTypeIR *>(old_type),
1042           static_cast<const FunctionTypeIR *>(new_type), diff_kind);
1043       // Do not allow extending function pointers, function references, etc.
1044       if (result.IsExtension()) {
1045         result.CombineWith(DiffStatus::kDirectDiff);
1046       }
1047       return result;
1048     }
1049     case LinkableMessageKind::FunctionKind:
1050     case LinkableMessageKind::GlobalVarKind:
1051       llvm::errs() << "Unexpected LinkableMessageKind: " << kind << "\n";
1052       ::exit(1);
1053   }
1054 }
1055 
CompareDistinctKindMessages(const TypeIR * old_type,const TypeIR * new_type)1056 static DiffStatus CompareDistinctKindMessages(
1057     const TypeIR *old_type, const TypeIR *new_type) {
1058   // For these types to be considered ABI compatible, the very least requirement
1059   // is that their sizes and alignments should be equal.
1060   // TODO: Fill in
1061   return DiffStatus::kDirectDiff;
1062 }
1063 
CompareAndDumpTypeDiff(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)1064 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
1065     const std::string &old_type_id, const std::string &new_type_id,
1066     DiffMessageIR::DiffKind diff_kind) {
1067   // Check the map for type ids which have already been compared
1068   // These types have already been diffed, return without further comparison.
1069   if (!type_cache_->insert(old_type_id + new_type_id).second) {
1070     return DiffStatus::kNoDiff;
1071   }
1072 
1073   TypeStackGuard guard(type_stack_,
1074                        ConvertTypeIdToString(old_types_, old_type_id));
1075 
1076   AbiElementMap<const TypeIR *>::const_iterator old_it =
1077       old_types_.find(old_type_id);
1078   AbiElementMap<const TypeIR *>::const_iterator new_it =
1079       new_types_.find(new_type_id);
1080 
1081   if (old_it == old_types_.end() || new_it == new_types_.end()) {
1082     // One of the types were hidden, we cannot compare further.
1083     return AreOpaqueTypesEqual(old_type_id, new_type_id)
1084                ? DiffStatus::kNoDiff
1085                : DiffStatus::kDirectDiff;
1086   }
1087 
1088   LinkableMessageKind old_kind = old_it->second->GetKind();
1089   LinkableMessageKind new_kind = new_it->second->GetKind();
1090   DiffStatus diff_status = DiffStatus::kNoDiff;
1091   if (old_kind != new_kind) {
1092     diff_status = CompareDistinctKindMessages(old_it->second, new_it->second);
1093   } else {
1094     diff_status = CompareAndDumpTypeDiff(old_it->second, new_it->second,
1095                                          old_kind, diff_kind);
1096   }
1097   return diff_status;
1098 }
1099 
1100 
1101 }  // namespace repr
1102 }  // namespace header_checker
1103