From 0482b27c6b005baffce34dc393c506a8908e9bbf Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 18 Mar 2026 12:11:42 -0400 Subject: [PATCH] Support more types in `MapConstantToAPValue` by refactoring code out of `ConvertArgToTemplateArg` (#6923) This doesn't change any of the current tests, but will be useful for calling constexpr functions with bool/float params. --- toolchain/check/cpp/call.cpp | 39 ++++++-------------------------- toolchain/check/cpp/constant.cpp | 29 ++++++++++++++++-------- toolchain/check/cpp/constant.h | 7 ++++++ 3 files changed, 34 insertions(+), 41 deletions(-) diff --git a/toolchain/check/cpp/call.cpp b/toolchain/check/cpp/call.cpp index 558583e91129..f37e2cc2b68d 100644 --- a/toolchain/check/cpp/call.cpp +++ b/toolchain/check/cpp/call.cpp @@ -8,6 +8,7 @@ #include "clang/Sema/Template.h" #include "toolchain/base/kind_switch.h" #include "toolchain/check/call.h" +#include "toolchain/check/cpp/constant.h" #include "toolchain/check/cpp/import.h" #include "toolchain/check/cpp/location.h" #include "toolchain/check/cpp/operators.h" @@ -227,38 +228,7 @@ static auto ConvertArgToTemplateArg( auto const_inst_id = context.constant_values().GetConstantInstId(converted_inst_id); if (const_inst_id.has_value()) { - if (param_type->isIntegerType()) { - const bool is_signed = param_type->isSignedIntegerOrEnumerationType(); - if (auto int_value = - context.insts().TryGetAs(const_inst_id)) { - const auto& ap_int = context.ints().Get(int_value->int_id); - auto aps_int = - llvm::APSInt(ap_int, !is_signed) - .extOrTrunc(context.ast_context().getIntWidth(param_type)); - clang::TemplateArgument template_arg(context.ast_context(), aps_int, - param_type); - return clang::TemplateArgumentLoc(template_arg, template_loc); - } else if (auto bool_value = - context.insts().TryGetAs( - const_inst_id)) { - llvm::APInt ap_int(context.ast_context().getIntWidth(param_type), - bool_value->value.ToBool(), is_signed); - auto aps_int = - llvm::APSInt(ap_int, !is_signed) - .extOrTrunc(context.ast_context().getIntWidth(param_type)); - auto template_arg = clang::TemplateArgument(context.ast_context(), - aps_int, param_type); - return clang::TemplateArgumentLoc(template_arg, template_loc); - } - } else if (param_type->isFloatingType()) { - if (auto float_value = - context.insts().TryGetAs(const_inst_id)) { - const auto& ap_float = context.floats().Get(float_value->float_id); - clang::TemplateArgument template_arg( - context.ast_context(), param_type, clang::APValue(ap_float)); - return clang::TemplateArgumentLoc(template_arg, template_loc); - } - } else if (param_type->isPointerType()) { + if (param_type->isPointerType()) { if (auto addr_of = context.insts().TryGetAs(const_inst_id)) { if (auto* var_decl = GetAsClangVarDecl(context, addr_of->lvalue_id)) { @@ -268,6 +238,11 @@ static auto ConvertArgToTemplateArg( // TODO: support pointers to variables declared in Carbon. } + } else if (auto ap_value = + MapConstantToAPValue(context, const_inst_id, param_type)) { + clang::TemplateArgument template_arg(context.ast_context(), param_type, + *ap_value); + return clang::TemplateArgumentLoc(template_arg, template_loc); } } diff --git a/toolchain/check/cpp/constant.cpp b/toolchain/check/cpp/constant.cpp index 143941d5bbed..2eddb00d8bc3 100644 --- a/toolchain/check/cpp/constant.cpp +++ b/toolchain/check/cpp/constant.cpp @@ -160,21 +160,32 @@ auto EvalCppVarDecl(Context& context, SemIR::LocId loc_id, return SemIR::ConstantId::NotConstant; } -static auto ConvertConstantToAPValue(Context& context, - SemIR::InstId const_inst_id, - clang::QualType param_type) +auto MapConstantToAPValue(Context& context, SemIR::InstId const_inst_id, + clang::QualType param_type) -> std::optional { if (param_type->isIntegerType()) { + const bool is_signed = param_type->isSignedIntegerOrEnumerationType(); if (auto int_value = context.insts().TryGetAs(const_inst_id)) { - const auto& ap_int = context.ints().GetAtWidth( - int_value->int_id, context.ast_context().getIntWidth(param_type)); - + const auto& ap_int = context.ints().Get(int_value->int_id); auto aps_int = - llvm::APSInt(ap_int, !param_type->isSignedIntegerOrEnumerationType()) + llvm::APSInt(ap_int, !is_signed) .extOrTrunc(context.ast_context().getIntWidth(param_type)); - return clang::APValue(aps_int); + } else if (auto bool_value = context.insts().TryGetAs( + const_inst_id)) { + llvm::APInt ap_int(context.ast_context().getIntWidth(param_type), + bool_value->value.ToBool(), is_signed); + auto aps_int = + llvm::APSInt(ap_int, !is_signed) + .extOrTrunc(context.ast_context().getIntWidth(param_type)); + return clang::APValue(aps_int); + } + } else if (param_type->isFloatingType()) { + if (auto float_value = + context.insts().TryGetAs(const_inst_id)) { + const auto& ap_float = context.floats().Get(float_value->float_id); + return clang::APValue(ap_float); } } @@ -189,7 +200,7 @@ static auto ConvertArgToExpr(Context& context, SemIR::InstId arg_inst_id, return nullptr; } - auto ap_value = ConvertConstantToAPValue(context, const_inst_id, param_type); + auto ap_value = MapConstantToAPValue(context, const_inst_id, param_type); if (!ap_value.has_value()) { return nullptr; } diff --git a/toolchain/check/cpp/constant.h b/toolchain/check/cpp/constant.h index 89a7fc8b8e32..6eb237bfb411 100644 --- a/toolchain/check/cpp/constant.h +++ b/toolchain/check/cpp/constant.h @@ -5,6 +5,8 @@ #ifndef CARBON_TOOLCHAIN_CHECK_CPP_CONSTANT_H_ #define CARBON_TOOLCHAIN_CHECK_CPP_CONSTANT_H_ +#include + #include "clang/AST/APValue.h" #include "toolchain/check/context.h" #include "toolchain/sem_ir/ids.h" @@ -16,6 +18,11 @@ auto MapAPValueToConstant(Context& context, SemIR::LocId loc_id, const clang::APValue& ap_value, clang::QualType type, bool is_lvalue) -> SemIR::ConstantId; +// Converts a Carbon constant instruction to an `APValue`. +auto MapConstantToAPValue(Context& context, SemIR::InstId const_inst_id, + clang::QualType param_type) + -> std::optional; + // Attempt to evaluate a C++ constexpr variable as a Carbon constant. auto EvalCppVarDecl(Context& context, SemIR::LocId loc_id, const clang::VarDecl* var_decl, SemIR::TypeId type_id)