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 
CompareCommonRecordFields(const RecordFieldIR * old_field,const RecordFieldIR * new_field,DiffMessageIR::DiffKind diff_kind)360 DiffStatus AbiDiffHelper::CompareCommonRecordFields(
361     const RecordFieldIR *old_field, const RecordFieldIR *new_field,
362     DiffMessageIR::DiffKind diff_kind) {
363   DiffStatus field_diff_status =
364       CompareAndDumpTypeDiff(old_field->GetReferencedType(),
365                              new_field->GetReferencedType(), diff_kind);
366   // CompareAndDumpTypeDiff should not return kDirectExt.
367   // In case it happens, report an incompatible diff for review.
368   if (field_diff_status.IsExtension() ||
369       old_field->GetOffset() != new_field->GetOffset() ||
370       old_field->IsBitField() != new_field->IsBitField() ||
371       old_field->GetBitWidth() != new_field->GetBitWidth()) {
372     field_diff_status.CombineWith(DiffStatus::kDirectDiff);
373   }
374   field_diff_status.CombineWith(
375       CompareAccess(old_field->GetAccess(), new_field->GetAccess()));
376   return field_diff_status;
377 }
378 
379 // This function filters out the pairs of old and new fields that meet the
380 // following conditions:
381 //   The old field's (offset, bit width, type) is unique in old_fields.
382 //   The new field's (offset, bit width, type) is unique in new_fields.
383 //   The two fields have compatible attributes except the name.
384 //
385 // This function returns either kNoDiff or kIndirectDiff. It is the status of
386 // the field pairs that are filtered out.
FilterOutRenamedRecordFields(DiffMessageIR::DiffKind diff_kind,std::vector<const RecordFieldIR * > & old_fields,std::vector<const RecordFieldIR * > & new_fields)387 DiffStatus AbiDiffHelper::FilterOutRenamedRecordFields(
388     DiffMessageIR::DiffKind diff_kind,
389     std::vector<const RecordFieldIR *> &old_fields,
390     std::vector<const RecordFieldIR *> &new_fields) {
391   DiffStatus diff_status = DiffStatus::kNoDiff;
392   const auto old_end = old_fields.end();
393   const auto new_end = new_fields.end();
394   auto is_less = [](const RecordFieldIR *first, const RecordFieldIR *second) {
395     if (first->GetOffset() != second->GetOffset()) {
396       return first->GetOffset() < second->GetOffset();
397     }
398     if (first->IsBitField() != second->IsBitField()) {
399       return first->IsBitField() < second->IsBitField();
400     }
401     if (first->GetBitWidth() != second->GetBitWidth()) {
402       return first->GetBitWidth() < second->GetBitWidth();
403     }
404     return first->GetReferencedType() < second->GetReferencedType();
405   };
406   std::sort(old_fields.begin(), old_end, is_less);
407   std::sort(new_fields.begin(), new_end, is_less);
408 
409   std::vector<const RecordFieldIR *> out_old_fields;
410   std::vector<const RecordFieldIR *> out_new_fields;
411   auto old_it = old_fields.begin();
412   auto new_it = new_fields.begin();
413   while (old_it != old_end && new_it != new_end) {
414     auto next_old_it = std::next(old_it);
415     while (next_old_it != old_end && !is_less(*old_it, *next_old_it)) {
416       next_old_it++;
417     }
418     if (is_less(*old_it, *new_it) || next_old_it - old_it > 1) {
419       out_old_fields.insert(out_old_fields.end(), old_it, next_old_it);
420       old_it = next_old_it;
421       continue;
422     }
423 
424     auto next_new_it = std::next(new_it);
425     while (next_new_it != new_end && !is_less(*new_it, *next_new_it)) {
426       next_new_it++;
427     }
428     if (is_less(*new_it, *old_it) || next_new_it - new_it > 1) {
429       out_new_fields.insert(out_new_fields.end(), new_it, next_new_it);
430       new_it = next_new_it;
431       continue;
432     }
433 
434     DiffStatus field_diff_status =
435         CompareCommonRecordFields(*old_it, *new_it, diff_kind);
436     if (field_diff_status.IsDirectDiff()) {
437       out_old_fields.emplace_back(*old_it);
438       out_new_fields.emplace_back(*new_it);
439     } else {
440       diff_status.CombineWith(field_diff_status);
441     }
442     old_it = next_old_it;
443     new_it = next_new_it;
444   }
445   out_old_fields.insert(out_old_fields.end(), old_it, old_end);
446   out_new_fields.insert(out_new_fields.end(), new_it, new_end);
447 
448   old_fields = std::move(out_old_fields);
449   new_fields = std::move(out_new_fields);
450   return diff_status;
451 }
452 
CompareRecordFields(const std::vector<RecordFieldIR> & old_fields,const std::vector<RecordFieldIR> & new_fields,DiffMessageIR::DiffKind diff_kind)453 RecordFieldDiffResult AbiDiffHelper::CompareRecordFields(
454     const std::vector<RecordFieldIR> &old_fields,
455     const std::vector<RecordFieldIR> &new_fields,
456     DiffMessageIR::DiffKind diff_kind) {
457   RecordFieldDiffResult result;
458   DiffStatus &diff_status = result.status;
459   diff_status = DiffStatus::kNoDiff;
460   // Map names to RecordFieldIR.
461   AbiElementMap<const RecordFieldIR *> old_fields_map;
462   AbiElementMap<const RecordFieldIR *> new_fields_map;
463 
464   auto get_field_name = [](const RecordFieldIR *f) -> std::string {
465     return !f->GetName().empty()
466                ? f->GetName()
467                : std::to_string(f->GetOffset()) + "#" + f->GetReferencedType();
468   };
469 
470   utils::AddToMap(&old_fields_map, old_fields, get_field_name,
471                   [](const RecordFieldIR *f) { return f; });
472   utils::AddToMap(&new_fields_map, new_fields, get_field_name,
473                   [](const RecordFieldIR *f) { return f; });
474   // Compare the fields whose names are not present in both records.
475   result.removed_fields =
476       utils::FindRemovedElements(old_fields_map, new_fields_map);
477   result.added_fields =
478       utils::FindRemovedElements(new_fields_map, old_fields_map);
479   diff_status.CombineWith(FilterOutRenamedRecordFields(
480       diff_kind, result.removed_fields, result.added_fields));
481   if (result.removed_fields.size() != 0) {
482     diff_status.CombineWith(DiffStatus::kDirectDiff);
483   }
484   if (result.added_fields.size() != 0) {
485     diff_status.CombineWith(DiffStatus::kDirectExt);
486   }
487   // Compare the fields whose names are present in both records.
488   std::vector<std::pair<const RecordFieldIR *, const RecordFieldIR *>> cf =
489       utils::FindCommonElements(old_fields_map, new_fields_map);
490   for (auto &&common_fields : cf) {
491     DiffStatus field_diff_status = CompareCommonRecordFields(
492         common_fields.first, common_fields.second, diff_kind);
493     diff_status.CombineWith(field_diff_status);
494     if (field_diff_status.IsDirectDiff()) {
495       result.diffed_fields.emplace_back(common_fields.first,
496                                         common_fields.second);
497     }
498   }
499   return result;
500 }
501 
CompareBaseSpecifiers(const std::vector<CXXBaseSpecifierIR> & old_base_specifiers,const std::vector<CXXBaseSpecifierIR> & new_base_specifiers,DiffMessageIR::DiffKind diff_kind)502 bool AbiDiffHelper::CompareBaseSpecifiers(
503     const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
504     const std::vector<CXXBaseSpecifierIR> &new_base_specifiers,
505     DiffMessageIR::DiffKind diff_kind) {
506   if (old_base_specifiers.size() != new_base_specifiers.size()) {
507     return false;
508   }
509   int i = 0;
510   while (i < old_base_specifiers.size()) {
511     if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(),
512                                new_base_specifiers.at(i).GetReferencedType(),
513                                diff_kind)
514             .IsDirectDiff() ||
515         (old_base_specifiers.at(i).GetAccess() !=
516          new_base_specifiers.at(i).GetAccess())) {
517       return false;
518     }
519     i++;
520   }
521   return true;
522 }
523 
CompareTemplateInfo(const std::vector<TemplateElementIR> & old_template_elements,const std::vector<TemplateElementIR> & new_template_elements,DiffMessageIR::DiffKind diff_kind)524 DiffStatus AbiDiffHelper::CompareTemplateInfo(
525     const std::vector<TemplateElementIR> &old_template_elements,
526     const std::vector<TemplateElementIR> &new_template_elements,
527     DiffMessageIR::DiffKind diff_kind) {
528   uint32_t old_template_size = old_template_elements.size();
529   uint32_t i = 0;
530   if (old_template_size != new_template_elements.size()) {
531     return DiffStatus::kDirectDiff;
532   }
533   DiffStatus final_diff_status = DiffStatus::kNoDiff;
534   while (i < old_template_size) {
535     const TemplateElementIR &old_template_element =
536         old_template_elements[i];
537     const TemplateElementIR &new_template_element =
538         new_template_elements[i];
539     auto template_element_diff = CompareAndDumpTypeDiff(
540         old_template_element.GetReferencedType(),
541         new_template_element.GetReferencedType(), diff_kind);
542     if (template_element_diff.HasDiff()) {
543       final_diff_status.CombineWith(template_element_diff);
544     }
545     i++;
546   }
547   return final_diff_status;
548 }
549 
550 template <typename DiffContainer, typename T>
ConvertToDiffContainerVector(std::vector<std::pair<T,T>> & nc_vector)551 static std::vector<DiffContainer> ConvertToDiffContainerVector(
552     std::vector<std::pair<T, T>> &nc_vector) {
553   std::vector<DiffContainer> cptr_vec;
554   for (auto &e : nc_vector) {
555     cptr_vec.emplace_back(&e.first, &e.second);
556   }
557   return cptr_vec;
558 }
559 
560 template <typename T>
ConvertToConstPtrVector(std::vector<T> & nc_vector)561 static std::vector<const T*> ConvertToConstPtrVector(
562     std::vector<T> &nc_vector) {
563   std::vector<const T*> cptr_vec;
564   for (auto &e : nc_vector) {
565     cptr_vec.emplace_back(&e);
566   }
567   return cptr_vec;
568 }
569 
FixupRemovedFieldTypeIds(const std::vector<const RecordFieldIR * > & removed_fields,const AbiElementMap<const TypeIR * > & old_types)570 static std::vector<RecordFieldIR> FixupRemovedFieldTypeIds(
571     const std::vector<const RecordFieldIR *> &removed_fields,
572     const AbiElementMap<const TypeIR *> &old_types) {
573   std::vector<RecordFieldIR> removed_fields_dup;
574   for (auto &removed_field : removed_fields) {
575     removed_fields_dup.emplace_back(*removed_field);
576     RecordFieldIR &it = removed_fields_dup[removed_fields_dup.size() -1];
577     it.SetReferencedType(
578         ConvertTypeIdToString(old_types, it.GetReferencedType()));
579   }
580   return removed_fields_dup;
581 }
582 
583 std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
FixupDiffedFieldTypeIds(const std::vector<RecordFieldDiffIR> & field_diffs)584 AbiDiffHelper::FixupDiffedFieldTypeIds(
585     const std::vector<RecordFieldDiffIR> &field_diffs) {
586   std::vector<std::pair<RecordFieldIR, RecordFieldIR>>
587       diffed_fields_dup;
588   for (auto &field_diff : field_diffs) {
589     diffed_fields_dup.emplace_back(*(field_diff.old_field_),
590                                    *(field_diff.new_field_));
591     auto &it = diffed_fields_dup[diffed_fields_dup.size() - 1];
592     RecordFieldIR &old_field = it.first;
593     RecordFieldIR &new_field = it.second;
594     old_field.SetReferencedType(
595         ConvertTypeIdToString(old_types_, old_field.GetReferencedType()));
596     new_field.SetReferencedType(
597         ConvertTypeIdToString(new_types_, new_field.GetReferencedType()));
598   }
599   return diffed_fields_dup;
600 }
601 
CompareFunctionTypes(const CFunctionLikeIR * old_type,const CFunctionLikeIR * new_type,DiffMessageIR::DiffKind diff_kind)602 DiffStatus AbiDiffHelper::CompareFunctionTypes(
603     const CFunctionLikeIR *old_type, const CFunctionLikeIR *new_type,
604     DiffMessageIR::DiffKind diff_kind) {
605   DiffStatus status = CompareFunctionParameters(
606       old_type->GetParameters(), new_type->GetParameters(), diff_kind);
607   status.CombineWith(CompareReturnTypes(old_type->GetReturnType(),
608                                         new_type->GetReturnType(), diff_kind));
609   return status;
610 }
611 
CompareRecordTypes(const RecordTypeIR * old_type,const RecordTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)612 DiffStatus AbiDiffHelper::CompareRecordTypes(
613     const RecordTypeIR *old_type, const RecordTypeIR *new_type,
614     DiffMessageIR::DiffKind diff_kind) {
615   auto record_type_diff_ir = std::make_unique<RecordTypeDiffIR>();
616   // Compare names.
617   if (!old_type->IsAnonymous() && !new_type->IsAnonymous() &&
618       old_type->GetLinkerSetKey() != new_type->GetLinkerSetKey()) {
619     // Do not dump anything since the record types themselves are fundamentally
620     // different.
621     return DiffStatus::kDirectDiff;
622   }
623   DiffStatus final_diff_status = DiffStatus::kNoDiff;
624   record_type_diff_ir->SetName(old_type->GetName());
625   record_type_diff_ir->SetLinkerSetKey(old_type->GetLinkerSetKey());
626 
627   DiffStatus access_diff_status =
628       CompareAccess(old_type->GetAccess(), new_type->GetAccess());
629   final_diff_status.CombineWith(access_diff_status);
630   if (access_diff_status.HasDiff()) {
631     record_type_diff_ir->SetAccessDiff(
632         std::make_unique<AccessSpecifierDiffIR>(
633             old_type->GetAccess(), new_type->GetAccess()));
634   }
635 
636   if (!CompareSizeAndAlignment(old_type, new_type)) {
637     if (old_type->GetSize() < new_type->GetSize() &&
638         old_type->GetAlignment() == new_type->GetAlignment()) {
639       final_diff_status.CombineWith(DiffStatus::kDirectExt);
640     } else {
641       final_diff_status.CombineWith(DiffStatus::kDirectDiff);
642     }
643     record_type_diff_ir->SetTypeDiff(
644         std::make_unique<TypeDiffIR>(
645             std::make_pair(old_type->GetSize(), new_type->GetSize()),
646             std::make_pair(old_type->GetAlignment(),
647                            new_type->GetAlignment())));
648   }
649 
650   const std::vector<VTableComponentIR> &old_vtable =
651       old_type->GetVTableLayout().GetVTableComponents();
652   const std::vector<VTableComponentIR> &new_vtable =
653       new_type->GetVTableLayout().GetVTableComponents();
654   if (!CompareVTables(old_vtable, new_vtable)) {
655     if (IsVTableExtended(old_vtable, new_vtable)) {
656       final_diff_status.CombineWith(DiffStatus::kDirectExt);
657     } else {
658       final_diff_status.CombineWith(DiffStatus::kDirectDiff);
659     }
660     record_type_diff_ir->SetVTableLayoutDiff(
661         std::make_unique<VTableLayoutDiffIR>(
662             old_type->GetVTableLayout(), new_type->GetVTableLayout()));
663   }
664 
665   auto &old_fields_dup = old_type->GetFields();
666   auto &new_fields_dup = new_type->GetFields();
667   RecordFieldDiffResult field_status_and_diffs =
668       CompareRecordFields(old_fields_dup, new_fields_dup, diff_kind);
669   final_diff_status.CombineWith(field_status_and_diffs.status);
670 
671   std::vector<CXXBaseSpecifierIR> old_bases = old_type->GetBases();
672   std::vector<CXXBaseSpecifierIR> new_bases = new_type->GetBases();
673   if (!CompareBaseSpecifiers(old_bases, new_bases, diff_kind) &&
674       ir_diff_dumper_) {
675     final_diff_status.CombineWith(DiffStatus::kDirectDiff);
676     ReplaceReferencesOtherTypeIdWithName(old_types_, old_bases);
677     ReplaceReferencesOtherTypeIdWithName(new_types_, new_bases);
678     record_type_diff_ir->SetBaseSpecifierDiffs(
679         std::make_unique<CXXBaseSpecifierDiffIR>(old_bases, new_bases));
680   }
681   if (ir_diff_dumper_) {
682     // Make copies of the fields removed and diffed, since we have to change
683     // type ids -> type strings.
684     std::vector<std::pair<RecordFieldIR, RecordFieldIR>> field_diff_dups =
685         FixupDiffedFieldTypeIds(field_status_and_diffs.diffed_fields);
686     std::vector<RecordFieldDiffIR> field_diffs_fixed =
687         ConvertToDiffContainerVector<RecordFieldDiffIR,
688                                      RecordFieldIR>(field_diff_dups);
689 
690     std::vector<RecordFieldIR> field_removed_dups = FixupRemovedFieldTypeIds(
691         field_status_and_diffs.removed_fields, old_types_);
692     std::vector<const RecordFieldIR *> fields_removed_fixed =
693         ConvertToConstPtrVector(field_removed_dups);
694 
695     std::vector<RecordFieldIR> field_added_dups = FixupRemovedFieldTypeIds(
696         field_status_and_diffs.added_fields, new_types_);
697     std::vector<const RecordFieldIR *> fields_added_fixed =
698         ConvertToConstPtrVector(field_added_dups);
699 
700     record_type_diff_ir->SetFieldDiffs(std::move(field_diffs_fixed));
701     record_type_diff_ir->SetFieldsRemoved(std::move(fields_removed_fixed));
702     record_type_diff_ir->SetFieldsAdded(std::move(fields_added_fixed));
703     record_type_diff_ir->SetExtended(final_diff_status.IsExtension());
704 
705     if (final_diff_status.IsDirectDiff() &&
706         !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
707                                            UnwindTypeStack(), diff_kind)) {
708       llvm::errs() << "AddDiffMessage on record type failed\n";
709       ::exit(1);
710     }
711   }
712 
713   final_diff_status.CombineWith(
714       CompareTemplateInfo(old_type->GetTemplateElements(),
715                           new_type->GetTemplateElements(), diff_kind));
716 
717   return (final_diff_status.HasDiff() ? DiffStatus::kIndirectDiff
718                                       : DiffStatus::kNoDiff);
719 }
720 
CompareLvalueReferenceTypes(const LvalueReferenceTypeIR * old_type,const LvalueReferenceTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)721 DiffStatus AbiDiffHelper::CompareLvalueReferenceTypes(
722     const LvalueReferenceTypeIR *old_type,
723     const LvalueReferenceTypeIR *new_type, DiffMessageIR::DiffKind diff_kind) {
724   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
725                                 new_type->GetReferencedType(), diff_kind);
726 }
727 
CompareRvalueReferenceTypes(const RvalueReferenceTypeIR * old_type,const RvalueReferenceTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)728 DiffStatus AbiDiffHelper::CompareRvalueReferenceTypes(
729     const RvalueReferenceTypeIR *old_type,
730     const RvalueReferenceTypeIR *new_type, DiffMessageIR::DiffKind diff_kind) {
731   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
732                                 new_type->GetReferencedType(), diff_kind);
733 }
734 
CompareQualifiedTypes(const QualifiedTypeIR * old_type,const QualifiedTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)735 DiffStatus AbiDiffHelper::CompareQualifiedTypes(
736     const QualifiedTypeIR *old_type, const QualifiedTypeIR *new_type,
737     DiffMessageIR::DiffKind diff_kind) {
738   // If all the qualifiers are not the same, return direct_diff, else
739   // recursively compare the unqualified types.
740   if (old_type->IsConst() != new_type->IsConst() ||
741       old_type->IsVolatile() != new_type->IsVolatile() ||
742       old_type->IsRestricted() != new_type->IsRestricted()) {
743     return DiffStatus::kDirectDiff;
744   }
745   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
746                                 new_type->GetReferencedType(), diff_kind);
747 }
748 
CompareArrayTypes(const ArrayTypeIR * old_type,const ArrayTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)749 DiffStatus AbiDiffHelper::CompareArrayTypes(const ArrayTypeIR *old_type,
750                                             const ArrayTypeIR *new_type,
751                                             DiffMessageIR::DiffKind diff_kind) {
752   if (!CompareSizeAndAlignment(old_type, new_type) ||
753       old_type->IsOfUnknownBound() != new_type->IsOfUnknownBound()) {
754     return DiffStatus::kDirectDiff;
755   }
756   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
757                                 new_type->GetReferencedType(), diff_kind);
758 }
759 
ComparePointerTypes(const PointerTypeIR * old_type,const PointerTypeIR * new_type,DiffMessageIR::DiffKind diff_kind)760 DiffStatus AbiDiffHelper::ComparePointerTypes(
761     const PointerTypeIR *old_type, const PointerTypeIR *new_type,
762     DiffMessageIR::DiffKind diff_kind) {
763   // The following need to be the same for two pointer types to be considered
764   // equivalent:
765   // 1) Number of pointer indirections are the same.
766   // 2) The ultimate pointee is the same.
767   assert(CompareSizeAndAlignment(old_type, new_type));
768   return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
769                                 new_type->GetReferencedType(), diff_kind);
770 }
771 
CompareBuiltinTypes(const BuiltinTypeIR * old_type,const BuiltinTypeIR * new_type)772 DiffStatus AbiDiffHelper::CompareBuiltinTypes(
773     const BuiltinTypeIR *old_type,
774     const BuiltinTypeIR *new_type) {
775   // If the size, alignment and is_unsigned are the same, return no_diff
776   // else return direct_diff.
777   if (!CompareSizeAndAlignment(old_type, new_type) ||
778       old_type->IsUnsigned() != new_type->IsUnsigned() ||
779       old_type->IsIntegralType() != new_type->IsIntegralType()) {
780     return DiffStatus::kDirectDiff;
781   }
782   return DiffStatus::kNoDiff;
783 }
784 
CompareFunctionParameters(const std::vector<ParamIR> & old_parameters,const std::vector<ParamIR> & new_parameters,DiffMessageIR::DiffKind diff_kind)785 DiffStatus AbiDiffHelper::CompareFunctionParameters(
786     const std::vector<ParamIR> &old_parameters,
787     const std::vector<ParamIR> &new_parameters,
788     DiffMessageIR::DiffKind diff_kind) {
789   size_t old_parameters_size = old_parameters.size();
790   if (old_parameters_size != new_parameters.size()) {
791     return DiffStatus::kDirectDiff;
792   }
793   DiffStatus result = DiffStatus::kNoDiff;
794   for (uint64_t i = 0; i < old_parameters_size; i++) {
795     const ParamIR &old_parameter = old_parameters.at(i);
796     const ParamIR &new_parameter = new_parameters.at(i);
797     result.CombineWith(CompareParameterTypes(old_parameter.GetReferencedType(),
798                                              new_parameter.GetReferencedType(),
799                                              diff_kind));
800     if (old_parameter.GetIsDefault() != new_parameter.GetIsDefault()) {
801       result.CombineWith(DiffStatus::kDirectDiff);
802     }
803   }
804   return result;
805 }
806 
FindTypeById(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)807 static const TypeIR *FindTypeById(
808     const AbiElementMap<const TypeIR *> &type_graph,
809     const std::string &type_id) {
810   auto it = type_graph.find(type_id);
811   return it == type_graph.end() ? nullptr : it->second;
812 }
813 
814 struct Qualifiers {
815   bool is_const = false;
816   bool is_restricted = false;
817   bool is_volatile = false;
818 
operator ==header_checker::repr::Qualifiers819   bool operator==(const Qualifiers &other) const {
820     return (is_const == other.is_const &&
821             is_restricted == other.is_restricted &&
822             is_volatile == other.is_volatile);
823   }
824 
operator !=header_checker::repr::Qualifiers825   bool operator!=(const Qualifiers &other) const { return !(*this == other); }
826 };
827 
828 // This function returns the qualifiers and sets type_id to the unqalified or
829 // opaque type.
ResolveQualifiers(const AbiElementMap<const TypeIR * > & types,std::string & type_id)830 static Qualifiers ResolveQualifiers(const AbiElementMap<const TypeIR *> &types,
831                                     std::string &type_id) {
832   Qualifiers qual;
833   while (true) {
834     const TypeIR *type_ir = FindTypeById(types, type_id);
835     if (type_ir == nullptr ||
836         type_ir->GetKind() != LinkableMessageKind::QualifiedTypeKind) {
837       return qual;
838     }
839     const QualifiedTypeIR *qualified_type_ir =
840         static_cast<const QualifiedTypeIR *>(type_ir);
841     qual.is_const |= qualified_type_ir->IsConst();
842     qual.is_restricted |= qualified_type_ir->IsRestricted();
843     qual.is_volatile |= qualified_type_ir->IsVolatile();
844     type_id = qualified_type_ir->GetReferencedType();
845   }
846 }
847 
848 // This function returns whether the old_type can be implicitly casted to
849 // new_type. It resolves qualified pointers and references until it reaches a
850 // type that does not reference other types. It does not compare the final
851 // referenced types.
852 //
853 // If this function returns true, old_type_id and new_type_id are set to the
854 // final referenced types. are_qualifiers_equal represents whether the
855 // qualifiers are exactly the same.
856 //
857 // If this function returns false, old_type_id, new_type_id, and
858 // are_qualifiers_equal do not have valid values.
859 //
860 // This function follows C++ standard to determine whether qualifiers can be
861 // casted. The rules are described in
862 // Section 7.5 Qualification conversions [conv.qual] in C++17 standard
863 // and
864 // https://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions
865 // 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)866 static bool ResolveImplicitlyConvertibleQualifiedReferences(
867     const AbiElementMap<const TypeIR *> &old_types,
868     const AbiElementMap<const TypeIR *> &new_types, std::string &old_type_id,
869     std::string &new_type_id, bool &are_qualifiers_equal) {
870   are_qualifiers_equal = true;
871   bool is_first_level = true;
872   bool is_const_since_second_level = true;
873   while (true) {
874     // Check qualifiers.
875     const Qualifiers old_qual = ResolveQualifiers(old_types, old_type_id);
876     const Qualifiers new_qual = ResolveQualifiers(new_types, new_type_id);
877     are_qualifiers_equal &= (old_qual == new_qual);
878     if (is_first_level) {
879       is_first_level = false;
880     } else {
881       if ((old_qual.is_const && !new_qual.is_const) ||
882           (old_qual.is_restricted && !new_qual.is_restricted) ||
883           (old_qual.is_volatile && !new_qual.is_volatile)) {
884         return false;
885       }
886       if (!is_const_since_second_level && old_qual != new_qual) {
887         return false;
888       }
889       is_const_since_second_level &= new_qual.is_const;
890     }
891     // Stop if the unqualified types differ or don't reference other types.
892     const TypeIR *old_type = FindTypeById(old_types, old_type_id);
893     const TypeIR *new_type = FindTypeById(new_types, new_type_id);
894     if (old_type == nullptr || new_type == nullptr) {
895       return true;
896     }
897     const LinkableMessageKind kind = old_type->GetKind();
898     if (kind != new_type->GetKind()) {
899       return true;
900     }
901     if (kind != LinkableMessageKind::PointerTypeKind &&
902         kind != LinkableMessageKind::LvalueReferenceTypeKind &&
903         kind != LinkableMessageKind::RvalueReferenceTypeKind) {
904       return true;
905     }
906     // Get the referenced types.
907     old_type_id = old_type->GetReferencedType();
908     new_type_id = new_type->GetReferencedType();
909   }
910 }
911 
CompareParameterTypes(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)912 DiffStatus AbiDiffHelper::CompareParameterTypes(
913     const std::string &old_type_id, const std::string &new_type_id,
914     DiffMessageIR::DiffKind diff_kind) {
915   // Compare size and alignment.
916   const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
917   const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
918   if (old_type_ir != nullptr && new_type_ir != nullptr &&
919       !CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
920     return DiffStatus::kDirectDiff;
921   }
922   // Allow the new parameter to be more qualified than the old parameter.
923   std::string old_referenced_type_id = old_type_id;
924   std::string new_referenced_type_id = new_type_id;
925   bool are_qualifiers_equal;
926   if (!ResolveImplicitlyConvertibleQualifiedReferences(
927           old_types_, new_types_, old_referenced_type_id,
928           new_referenced_type_id, are_qualifiers_equal)) {
929     return DiffStatus::kDirectDiff;
930   }
931   // Compare the unqualified referenced types.
932   DiffStatus result = CompareAndDumpTypeDiff(old_referenced_type_id,
933                                              new_referenced_type_id, diff_kind);
934   if (!are_qualifiers_equal) {
935     result.CombineWith(DiffStatus::kDirectExt);
936   }
937   return result;
938 }
939 
940 // This function is the same as CompareParameterTypes except for the arguments
941 // to ResolveImplicitlyConvertibleQualifiedReferences.
CompareReturnTypes(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)942 DiffStatus AbiDiffHelper::CompareReturnTypes(
943     const std::string &old_type_id, const std::string &new_type_id,
944     DiffMessageIR::DiffKind diff_kind) {
945   // Compare size and alignment.
946   const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
947   const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
948   if (old_type_ir != nullptr && new_type_ir != nullptr &&
949       !CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
950     return DiffStatus::kDirectDiff;
951   }
952   // Allow the new return type to be less qualified than the old return type.
953   std::string old_referenced_type_id = old_type_id;
954   std::string new_referenced_type_id = new_type_id;
955   bool are_qualifiers_equal;
956   if (!ResolveImplicitlyConvertibleQualifiedReferences(
957           new_types_, old_types_, new_referenced_type_id,
958           old_referenced_type_id, are_qualifiers_equal)) {
959     return DiffStatus::kDirectDiff;
960   }
961   // Compare the unqualified referenced types.
962   DiffStatus result = CompareAndDumpTypeDiff(old_referenced_type_id,
963                                              new_referenced_type_id, diff_kind);
964   if (!are_qualifiers_equal) {
965     result.CombineWith(DiffStatus::kDirectExt);
966   }
967   return result;
968 }
969 
CompareAndDumpTypeDiff(const TypeIR * old_type,const TypeIR * new_type,LinkableMessageKind kind,DiffMessageIR::DiffKind diff_kind)970 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
971     const TypeIR *old_type, const TypeIR *new_type, LinkableMessageKind kind,
972     DiffMessageIR::DiffKind diff_kind) {
973   if (ignored_linker_set_keys_.find(new_type->GetLinkerSetKey()) !=
974       ignored_linker_set_keys_.end()) {
975     return DiffStatus::kNoDiff;
976   }
977 
978   switch (kind) {
979     case LinkableMessageKind::BuiltinTypeKind:
980       return CompareBuiltinTypes(static_cast<const BuiltinTypeIR *>(old_type),
981                                  static_cast<const BuiltinTypeIR *>(new_type));
982     case LinkableMessageKind::QualifiedTypeKind:
983       return CompareQualifiedTypes(
984           static_cast<const QualifiedTypeIR *>(old_type),
985           static_cast<const QualifiedTypeIR *>(new_type), diff_kind);
986     case LinkableMessageKind::ArrayTypeKind:
987       return CompareArrayTypes(static_cast<const ArrayTypeIR *>(old_type),
988                                static_cast<const ArrayTypeIR *>(new_type),
989                                diff_kind);
990     case LinkableMessageKind::EnumTypeKind:
991       return CompareEnumTypes(static_cast<const EnumTypeIR *>(old_type),
992                               static_cast<const EnumTypeIR *>(new_type),
993                               diff_kind);
994 
995     case LinkableMessageKind::LvalueReferenceTypeKind:
996       return CompareLvalueReferenceTypes(
997           static_cast<const LvalueReferenceTypeIR *>(old_type),
998           static_cast<const LvalueReferenceTypeIR *>(new_type), diff_kind);
999     case LinkableMessageKind::RvalueReferenceTypeKind:
1000       return CompareRvalueReferenceTypes(
1001           static_cast<const RvalueReferenceTypeIR *>(old_type),
1002           static_cast<const RvalueReferenceTypeIR *>(new_type), diff_kind);
1003     case LinkableMessageKind::PointerTypeKind:
1004       return ComparePointerTypes(static_cast<const PointerTypeIR *>(old_type),
1005                                  static_cast<const PointerTypeIR *>(new_type),
1006                                  diff_kind);
1007 
1008     case LinkableMessageKind::RecordTypeKind:
1009       return CompareRecordTypes(static_cast<const RecordTypeIR *>(old_type),
1010                                 static_cast<const RecordTypeIR *>(new_type),
1011                                 diff_kind);
1012 
1013     case LinkableMessageKind::FunctionTypeKind: {
1014       DiffStatus result = CompareFunctionTypes(
1015           static_cast<const FunctionTypeIR *>(old_type),
1016           static_cast<const FunctionTypeIR *>(new_type), diff_kind);
1017       // Do not allow extending function pointers, function references, etc.
1018       if (result.IsExtension()) {
1019         result.CombineWith(DiffStatus::kDirectDiff);
1020       }
1021       return result;
1022     }
1023     case LinkableMessageKind::FunctionKind:
1024     case LinkableMessageKind::GlobalVarKind:
1025       llvm::errs() << "Unexpected LinkableMessageKind: " << kind << "\n";
1026       ::exit(1);
1027   }
1028 }
1029 
CompareDistinctKindMessages(const TypeIR * old_type,const TypeIR * new_type)1030 static DiffStatus CompareDistinctKindMessages(
1031     const TypeIR *old_type, const TypeIR *new_type) {
1032   // For these types to be considered ABI compatible, the very least requirement
1033   // is that their sizes and alignments should be equal.
1034   // TODO: Fill in
1035   return DiffStatus::kDirectDiff;
1036 }
1037 
CompareAndDumpTypeDiff(const std::string & old_type_id,const std::string & new_type_id,DiffMessageIR::DiffKind diff_kind)1038 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
1039     const std::string &old_type_id, const std::string &new_type_id,
1040     DiffMessageIR::DiffKind diff_kind) {
1041   // Check the map for type ids which have already been compared
1042   // These types have already been diffed, return without further comparison.
1043   if (!type_cache_->insert(old_type_id + new_type_id).second) {
1044     return DiffStatus::kNoDiff;
1045   }
1046 
1047   TypeStackGuard guard(type_stack_,
1048                        ConvertTypeIdToString(old_types_, old_type_id));
1049 
1050   AbiElementMap<const TypeIR *>::const_iterator old_it =
1051       old_types_.find(old_type_id);
1052   AbiElementMap<const TypeIR *>::const_iterator new_it =
1053       new_types_.find(new_type_id);
1054 
1055   if (old_it == old_types_.end() || new_it == new_types_.end()) {
1056     // One of the types were hidden, we cannot compare further.
1057     return AreOpaqueTypesEqual(old_type_id, new_type_id)
1058                ? DiffStatus::kNoDiff
1059                : DiffStatus::kDirectDiff;
1060   }
1061 
1062   LinkableMessageKind old_kind = old_it->second->GetKind();
1063   LinkableMessageKind new_kind = new_it->second->GetKind();
1064   DiffStatus diff_status = DiffStatus::kNoDiff;
1065   if (old_kind != new_kind) {
1066     diff_status = CompareDistinctKindMessages(old_it->second, new_it->second);
1067   } else {
1068     diff_status = CompareAndDumpTypeDiff(old_it->second, new_it->second,
1069                                          old_kind, diff_kind);
1070   }
1071   return diff_status;
1072 }
1073 
1074 
1075 }  // namespace repr
1076 }  // namespace header_checker
1077