| 22 | : type_abi(abi_) {} |
| 23 | |
| 24 | std::unordered_map<const clang::Type*, TypeInfo> |
| 25 | ComputeDataLayout(const clang::ASTContext& context, const std::unordered_map<const clang::Type*, AnalysisAction::RepackedType>& types) { |
| 26 | std::unordered_map<const clang::Type*, TypeInfo> layout; |
| 27 | |
| 28 | // First, add all types directly used in function signatures of the library API to the meta set |
| 29 | for (const auto& [type, type_repack_info] : types) { |
| 30 | if (type_repack_info.assumed_compatible) { |
| 31 | auto [_, inserted] = layout.insert(std::pair {context.getCanonicalType(type), TypeInfo {}}); |
| 32 | if (!inserted) { |
| 33 | throw std::runtime_error( |
| 34 | "Failed to gather type metadata: Opaque type \"" + clang::QualType {type, 0}.getAsString() + "\" already registered"); |
| 35 | } |
| 36 | continue; |
| 37 | } |
| 38 | |
| 39 | if (type->isIncompleteType()) { |
| 40 | throw std::runtime_error( |
| 41 | "Cannot compute data layout of incomplete type \"" + clang::QualType {type, 0}.getAsString() + "\". Did you forget any annotations?"); |
| 42 | } |
| 43 | |
| 44 | if (type->isStructureType()) { |
| 45 | StructInfo info; |
| 46 | info.size_bits = context.getTypeSize(type); |
| 47 | info.alignment_bits = context.getTypeAlign(type); |
| 48 | |
| 49 | auto [_, inserted] = layout.insert(std::pair {context.getCanonicalType(type), info}); |
| 50 | if (!inserted) { |
| 51 | throw std::runtime_error("Failed to gather type metadata: Type \"" + clang::QualType {type, 0}.getAsString() + "\" already registered"); |
| 52 | } |
| 53 | } else if (type->isBuiltinType() || type->isEnumeralType()) { |
| 54 | SimpleTypeInfo info; |
| 55 | info.size_bits = context.getTypeSize(type); |
| 56 | info.alignment_bits = context.getTypeAlign(type); |
| 57 | |
| 58 | // NOTE: Non-enum types are intentionally not canonicalized since that would turn e.g. size_t into platform-specific types |
| 59 | auto [_, inserted] = layout.insert(std::pair {type->isEnumeralType() ? context.getCanonicalType(type) : type, info}); |
| 60 | if (!inserted) { |
| 61 | throw std::runtime_error("Failed to gather type metadata: Type \"" + clang::QualType {type, 0}.getAsString() + "\" already registered"); |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | // Then, add information about members |
| 67 | for (const auto& [type, type_repack_info] : types) { |
| 68 | if (!type->isStructureType() || type_repack_info.assumed_compatible) { |
| 69 | continue; |
| 70 | } |
| 71 | |
| 72 | auto& info = *layout.at(context.getCanonicalType(type)).get_if_struct(); |
| 73 | |
| 74 | for (auto* field : type->getAsStructureType()->getDecl()->fields()) { |
| 75 | auto field_type = field->getType().getTypePtr(); |
| 76 | std::optional<uint64_t> array_size; |
| 77 | if (auto array_type = llvm::dyn_cast<clang::ConstantArrayType>(field->getType())) { |
| 78 | array_size = array_type->getSize().getZExtValue(); |
| 79 | field_type = array_type->getElementType().getTypePtr(); |
| 80 | if (llvm::isa<clang::ConstantArrayType>(field_type)) { |
| 81 | throw std::runtime_error("Unsupported multi-dimensional array member \"" + field->getNameAsString() + "\" in type \"" + |
no test coverage detected