Repository: carbon-language/carbon-lang
File: toolchain/check/cpp/call.cpp (C++)

Code before:
  if (isa<clang::NonTypeTemplateParmDecl>(param_decl)) {
    auto non_type = cast<clang::NonTypeTemplateParmDecl>(param_decl);
    auto param_type = non_type->getType();

    // Handle integer parameters.
    if (param_type.getTypePtr()->isIntegerType()) {
      // Get the Carbon type corresponding to the parameter's Clang type.
      const TypeExpr type_expr =
          ImportCppType(context, SemIR::LocId(arg_id), param_type);

      // Try to convert the argument to the parameter type.
      const SemIR::InstId converted_inst_id =
          Convert(context, SemIR::LocId(arg_id), arg_id,
                  {
                      .kind = ConversionTarget::Value,
                      .type_id = type_expr.type_id,
                  });

      if (converted_inst_id.has_value()) {
        auto const_inst_id =
            context.constant_values().GetConstantInstId(converted_inst_id);
        if (const_inst_id.has_value()) {
          if (auto int_value =
                  context.insts().TryGetAs<SemIR::IntValue>(const_inst_id)) {
            const llvm::APInt ap_int = context.ints().Get(int_value->int_id);
            auto aps_int = llvm::APSInt(ap_int).extOrTrunc(
                context.ast_context().getIntWidth(param_type));
            auto template_arg = clang::TemplateArgument(context.ast_context(),
                                                        aps_int, param_type);
            // TODO: provide a better location.
            auto loc = clang::TemplateArgumentLocInfo();
            return clang::TemplateArgumentLoc(template_arg, loc);
          }
        }
      }
    }

    // TODO: Support other types.
    context.TODO(arg_id,
                 "unsupported argument type for non-type template parameter");
    return std::nullopt;
  }

  CARBON_FATAL("Unknown declaration kind for template parameter");
}

// Converts a call argument list into a Clang template argument list for a given
// template. Returns true on success, or false if an error was diagnosed.
static auto ConvertArgsToTemplateArgs(Context& context,
                                      clang::TemplateDecl* template_decl,
                                      llvm::ArrayRef<SemIR::InstId> arg_ids,

Review comment (suggestion):
I think Clang probably wants the `APSInt`'s `is_signed` flag to match the signedness of the template parameter, so we should set it here. I think `param_type->isSignedIntegerOrEnumerationType()` would do what you want.

(The difference between `APInt` and `APSInt` is that `APInt` is just tracking the sequence of bits in the integer, whereas `APSInt` also tracks a bool that indicates whether the integer is being interpreted as signed or unsigned.)

Code after:
  if (const auto* non_type =
          dyn_cast<clang::NonTypeTemplateParmDecl>(param_decl)) {
    auto param_type = non_type->getType();

    // Handle integer parameters.
    if (param_type->isIntegerType()) {
      // Get the Carbon type corresponding to the parameter's Clang type.
      const auto type_expr =
          ImportCppType(context, SemIR::LocId(arg_id), param_type);

      // Try to convert the argument to the parameter type.
      const auto converted_inst_id =
          Convert(context, SemIR::LocId(arg_id), arg_id,
                  {
                      .kind = ConversionTarget::Value,
                      .type_id = type_expr.type_id,
                  });

      if (converted_inst_id == SemIR::ErrorInst::InstId) {
        return std::nullopt;
      }

      auto const_inst_id =
          context.constant_values().GetConstantInstId(converted_inst_id);
      if (const_inst_id.has_value()) {
        if (auto int_value =
                context.insts().TryGetAs<SemIR::IntValue>(const_inst_id)) {
          const auto& ap_int = context.ints().Get(int_value->int_id);
          const bool is_unsigned =
              !param_type->isSignedIntegerOrEnumerationType();
          auto aps_int =
              llvm::APSInt(ap_int, is_unsigned)
                  .extOrTrunc(context.ast_context().getIntWidth(param_type));
          auto template_arg = clang::TemplateArgument(context.ast_context(),
                                                      aps_int, param_type);
          // TODO: provide a better location.
          auto loc = clang::TemplateArgumentLocInfo();
          return clang::TemplateArgumentLoc(template_arg, loc);
        }
      }
    }

    // TODO: Support other types.
    context.TODO(arg_id,
                 "unsupported argument type for non-type template parameter");
    return std::nullopt;
  }

  CARBON_FATAL("Unknown declaration kind for template parameter");
}