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

Code before:
    }

    // TODO: Eventually we should also support passing Carbon generics as
    // template template arguments.
    return MakePlaceholderTemplateArg(context, arg_id);
  }

  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");

Review comment (bug):
`Convert` should never return `None`. On failure it will return the sentinel value `SemIR::ErrorInst::InstId`, which indicates that an error has been detected and a diagnostic has already been issued. If you see that here, it looks like returning `nullopt` would be the way to tell the caller that an error has been diagnosed.

Code after:
    }

    // TODO: Eventually we should also support passing Carbon generics as
    // template template arguments.
    return MakePlaceholderTemplateArg(context, arg_id);
  }

  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,