| 136 | }; |
| 137 | |
| 138 | void GenerateThunkLibsAction::EmitLayoutWrappers(clang::ASTContext& context, std::ofstream& file, |
| 139 | std::unordered_map<const clang::Type*, TypeCompatibility>& type_compat) { |
| 140 | // Sort struct types by dependency so that repacking code is emitted in an order that compiles fine |
| 141 | std::vector<std::pair<const clang::Type*, RepackedType>> types {this->types.begin(), this->types.end()}; |
| 142 | BubbleSort(types.begin(), types.end(), compare_by_struct_dependency {context}); |
| 143 | |
| 144 | for (const auto& [type, type_repack_info] : types) { |
| 145 | auto struct_name = get_type_name(context, type); |
| 146 | |
| 147 | // Opaque types don't need layout definitions |
| 148 | if (type_repack_info.assumed_compatible && type_repack_info.pointers_only && struct_name != "void") { |
| 149 | if (guest_abi.pointer_size != 4) { |
| 150 | fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}*> = true;\n", struct_name); |
| 151 | } |
| 152 | continue; |
| 153 | } else if (type_repack_info.assumed_compatible) { |
| 154 | // TODO: Handle more cleanly |
| 155 | type_compat[type] = TypeCompatibility::Full; |
| 156 | } |
| 157 | |
| 158 | // These must be handled later since they are not canonicalized and hence must be de-duplicated first |
| 159 | if (type->isBuiltinType()) { |
| 160 | continue; |
| 161 | } |
| 162 | |
| 163 | // TODO: Instead, map these names back to *some* type that's named? |
| 164 | if (struct_name.starts_with("unnamed_")) { |
| 165 | continue; |
| 166 | } |
| 167 | |
| 168 | if (type->isEnumeralType()) { |
| 169 | fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name); |
| 170 | fmt::print(file, " using type = {}int{}_t;\n", type->isUnsignedIntegerOrEnumerationType() ? "u" : "", |
| 171 | guest_abi.at(struct_name).get_if_simple_or_struct()->size_bits); |
| 172 | fmt::print(file, " type data;\n"); |
| 173 | fmt::print(file, "}};\n"); |
| 174 | continue; |
| 175 | } |
| 176 | |
| 177 | if (type_compat.at(type) == TypeCompatibility::None && !type_repack_info.emit_layout_wrappers) { |
| 178 | // Disallow use of layout wrappers for this type by specializing without a definition |
| 179 | fmt::print(file, "template<>\nstruct guest_layout<{}>;\n", struct_name); |
| 180 | fmt::print(file, "template<>\nstruct host_layout<{}>;\n", struct_name); |
| 181 | fmt::print(file, "guest_layout<{}>& to_guest(const host_layout<{}>&) = delete;\n", struct_name, struct_name); |
| 182 | continue; |
| 183 | } |
| 184 | |
| 185 | // Guest layout definition |
| 186 | // NOTE: uint64_t has lower alignment requirements on 32-bit than on 64-bit, so we require tightly packed structs |
| 187 | // TODO: Now we must emit padding bytes explicitly, though! |
| 188 | fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name); |
| 189 | if (type_compat.at(type) == TypeCompatibility::Full) { |
| 190 | fmt::print(file, " using type = {};\n", struct_name); |
| 191 | } else { |
| 192 | fmt::print(file, " struct type {{\n"); |
| 193 | for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) { |
| 194 | fmt::print(file, " guest_layout<{}{}> {};\n", member.type_name, |
| 195 | member.array_size ? fmt::format("[{}]", member.array_size.value()) : "", member.member_name); |
nothing calls this directly
no test coverage detected