| 207 | } |
| 208 | |
| 209 | void AnalysisAction::ParseInterface(clang::ASTContext& context) { |
| 210 | ErrorReporter report_error {context}; |
| 211 | |
| 212 | const std::unordered_map<unsigned, ParameterAnnotations> no_param_annotations {}; |
| 213 | |
| 214 | // TODO: Assert fex_gen_type is not declared at non-global namespaces |
| 215 | if (auto template_decl = FindClassTemplateDeclByName(*context.getTranslationUnitDecl(), "fex_gen_type")) { |
| 216 | for (auto* decl : template_decl->specializations()) { |
| 217 | const auto& template_args = decl->getTemplateArgs(); |
| 218 | assert(template_args.size() == 1); |
| 219 | |
| 220 | // NOTE: Function types that are equivalent but use differently |
| 221 | // named types (e.g. GLuint/GLenum) are represented by |
| 222 | // different Type instances. The canonical type they refer |
| 223 | // to is unique, however. |
| 224 | clang::QualType type = context.getCanonicalType(template_args[0].getAsType()); |
| 225 | type = type->getLocallyUnqualifiedSingleStepDesugaredType(); |
| 226 | |
| 227 | const auto annotations = GetTypeAnnotations(context, decl); |
| 228 | if (type->isFunctionPointerType() || type->isFunctionType()) { |
| 229 | if (decl->getNumBases()) { |
| 230 | throw report_error(decl->getBeginLoc(), "Function pointer types cannot be annotated"); |
| 231 | } |
| 232 | thunked_funcptrs[type.getAsString()] = std::pair {type.getTypePtr(), no_param_annotations}; |
| 233 | } else { |
| 234 | RepackedType repack_info = {.assumed_compatible = annotations.is_opaque || annotations.assumed_compatible, |
| 235 | .pointers_only = annotations.is_opaque && !annotations.assumed_compatible, |
| 236 | .emit_layout_wrappers = annotations.emit_layout_wrappers}; |
| 237 | [[maybe_unused]] auto [it, inserted] = types.emplace(context.getCanonicalType(type.getTypePtr()), repack_info); |
| 238 | assert(inserted); |
| 239 | } |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | // Process function parameter annotations |
| 244 | std::unordered_map<const clang::FunctionDecl*, std::unordered_map<unsigned, ParameterAnnotations>> param_annotations; |
| 245 | for (auto& decl_context : decl_contexts) { |
| 246 | if (auto template_decl = FindClassTemplateDeclByName(*decl_context, "fex_gen_param")) { |
| 247 | for (auto* decl : template_decl->specializations()) { |
| 248 | const auto& template_args = decl->getTemplateArgs(); |
| 249 | assert(template_args.size() == 3); |
| 250 | |
| 251 | auto function = llvm::dyn_cast<clang::FunctionDecl>(template_args[0].getAsDecl()); |
| 252 | auto param_idx = template_args[1].getAsIntegral().getSExtValue(); |
| 253 | clang::QualType type = context.getCanonicalType(template_args[2].getAsType()); |
| 254 | type = type->getLocallyUnqualifiedSingleStepDesugaredType(); |
| 255 | |
| 256 | if (param_idx >= function->getNumParams() || param_idx < -1) { |
| 257 | throw report_error(GetTemplateArgLocation(decl, 1), "Out-of-bounds parameter index passed to fex_gen_param"); |
| 258 | } |
| 259 | |
| 260 | auto expected_type = param_idx == -1 ? function->getReturnType() : function->getParamDecl(param_idx)->getType(); |
| 261 | |
| 262 | if (!type->isVoidType() && !context.hasSameType(type, expected_type)) { |
| 263 | auto loc = param_idx == -1 ? function->getReturnTypeSourceRange().getBegin() : |
| 264 | function->getParamDecl(param_idx)->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); |
| 265 | throw report_error(GetTemplateArgLocation(decl, 2), "Type passed to fex_gen_param doesn't match the function signature") |
| 266 | .addNote(report_error(loc, "Expected this type instead")); |
nothing calls this directly
no test coverage detected