Quellcode durchsuchen

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.
Nicholas Bishop vor 1 Monat
Ursprung
Commit
0482b27c6b
3 geänderte Dateien mit 34 neuen und 41 gelöschten Zeilen
  1. 7 32
      toolchain/check/cpp/call.cpp
  2. 20 9
      toolchain/check/cpp/constant.cpp
  3. 7 0
      toolchain/check/cpp/constant.h

+ 7 - 32
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<SemIR::IntValue>(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<SemIR::BoolLiteral>(
-                           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<SemIR::FloatValue>(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<SemIR::AddrOf>(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);
       }
     }
 

+ 20 - 9
toolchain/check/cpp/constant.cpp

@@ -160,22 +160,33 @@ 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<clang::APValue> {
   if (param_type->isIntegerType()) {
+    const bool is_signed = param_type->isSignedIntegerOrEnumerationType();
     if (auto int_value =
             context.insts().TryGetAs<SemIR::IntValue>(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<SemIR::BoolLiteral>(
+                   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<SemIR::FloatValue>(const_inst_id)) {
+      const auto& ap_float = context.floats().Get(float_value->float_id);
+      return clang::APValue(ap_float);
+    }
   }
 
   // TODO: support additional parameter types.
@@ -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;
   }

+ 7 - 0
toolchain/check/cpp/constant.h

@@ -5,6 +5,8 @@
 #ifndef CARBON_TOOLCHAIN_CHECK_CPP_CONSTANT_H_
 #define CARBON_TOOLCHAIN_CHECK_CPP_CONSTANT_H_
 
+#include <optional>
+
 #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<clang::APValue>;
+
 // 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)