Repository: apple/swift
File: lib/ClangImporter/ClangImporter.cpp (C++)

Code before:
      if (i < numAttrs - 2)
        os << ", ";
      else if (i == numAttrs - 2)
        os << " or ";
    }
    return result;
  };

  if (!decl->hasAttrs())
    return;

  for (auto groupOfAttrs : ConflictingSwiftAttrs) {
    unsigned count = 0;
    for (auto attrName : groupOfAttrs) {
      if (isConditionalAttr(attrName)) {
        std::set<StringRef> conditionalParams;
        unsigned numConditionalAttrs =
            getConditionalAttrParams(decl, attrName, conditionalParams);
        if (numConditionalAttrs == 0)
          continue;
        count += numConditionalAttrs;

        auto specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
        if (!specDecl) {
          impl.diagnose(HeaderLoc{decl->getLocation()},
                        diag::invalid_conditional_attr, attrName);
          continue;
        }

        SmallVector<std::pair<unsigned, StringRef>, 4> argumentsToCheck;
        while (specDecl && !conditionalParams.empty()) {
          auto templateDecl = specDecl->getSpecializedTemplate();
          for (auto [idx, param] :
               llvm::enumerate(*templateDecl->getTemplateParameters())) {
            if (conditionalParams.erase(param->getName()))
              argumentsToCheck.push_back(std::make_pair(idx, param->getName()));
          }

          const clang::DeclContext *dc = specDecl;
          specDecl = nullptr;
          while ((dc = dc->getParent())) {
            specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
            if (specDecl)
              break;
          }
        }

        for (auto name : conditionalParams)
          impl.diagnose(HeaderLoc{decl->getLocation()},
                        diag::unknown_template_parameter, name);
      } else {

Review comment (performance):
Would it add a lot of complexity to get the location of the attr itself, rather than the decl location?

Code after:
    return;

  for (const auto &groupOfAttrs : ConflictingSwiftAttrs) {
    // stores this decl's attributes, grouped by annotation kind
    llvm::StringMap<std::vector<clang::SwiftAttrAttr *>> found;
    unsigned count = 0;
    for (auto [attrName, annotationName] : groupOfAttrs) {
      for (auto attr : decl->getAttrs()) {
        auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr);
        if (swiftAttr && swiftAttr->getAttribute().starts_with(attrName)) {
          found[annotationName].push_back(swiftAttr);
          count += 1;

          // in the common case, we validate at most one conditional attribute
          if (isConditionalAttr(attrName)) {
            auto specDecl =
                dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
            if (!specDecl) {
              diagnose(HeaderLoc{swiftAttr->getLocation()},
                       diag::invalid_conditional_attr, annotationName);
              continue;
            }
            auto conditionalParams =
                getConditionalAttrParams(swiftAttr, attrName);
            while (specDecl && !conditionalParams.empty()) {
              auto templateDecl = specDecl->getSpecializedTemplate();
              for (auto [idx, param] :
                   llvm::enumerate(*templateDecl->getTemplateParameters()))
                conditionalParams.erase(param->getName());

              const clang::DeclContext *dc = specDecl;
              specDecl = nullptr;
              while ((dc = dc->getParent())) {
                specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
                if (specDecl)
                  break;
              }
            }
            for (auto name : conditionalParams)
              diagnose(HeaderLoc{decl->getLocation()},
                       diag::unknown_template_parameter, name);
          }
        }
      }
    }

    if (count > 1) {
      if (found.size() == 1)
        diagnose(HeaderLoc{decl->getLocation()}, diag::repeating_swift_attrs,
                 found.begin()->getKey(), decl);
      else