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