Răsfoiți Sursa

Add support for using C++ `double` type in imported function declarations (#5868)

Carbon only supports f64, so only double can be mapped.

https://github.com/carbon-language/carbon-lang/blob/30f0ddab71bda71f8789080962b1fe8a5938e327/toolchain/check/type.cpp#L54

C++ Interop Demo:

```c++
// hello_world.h

auto hello_world(double x) -> void;
```

```c++
// hello_world.cpp

#include "hello_world.h"

#include <cstdio>

auto hello_world(double x) -> void {
  printf("double: %f\n", x);
}
```

```carbon
// main.carbon

library "Main";

import Cpp library "hello_world.h";

fn Run() -> i32 {
  Cpp.hello_world(0.25);
  return 0;
}
```

```shell
$ clang -c hello_world.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo
$ $ ./demo
double: 0.250000
```

Before this change:

```shell
$ bazel-bin/toolchain/carbon compile main.carbon
main.carbon:8:3: error: semantics TODO: `Unsupported: parameter type: double`
  Cpp.hello_world(0.25);
  ^~~~~~~~~~~~~~~
main.carbon:8:3: note: in `Cpp` name lookup for `hello_world`
  Cpp.hello_world(0.25);
  ^~~~~~~~~~~~~~~
```

Part of #5263.
Boaz Brickner 9 luni în urmă
părinte
comite
f0cff612eb

+ 3 - 3
toolchain/check/handle_literal.cpp

@@ -12,6 +12,7 @@
 #include "toolchain/check/name_lookup.h"
 #include "toolchain/check/type.h"
 #include "toolchain/diagnostics/format_providers.h"
+#include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::Check {
@@ -147,9 +148,8 @@ auto HandleParseNode(Context& context, Parse::FloatTypeLiteralId node_id)
   }
   auto tok_id = context.parse_tree().node_token(node_id);
   auto size_id = context.tokens().GetTypeLiteralSize(tok_id);
-  auto width_id = MakeIntLiteral(context, node_id, size_id);
-  auto fn_inst_id = LookupNameInCore(context, node_id, "Float");
-  auto type_inst_id = PerformCall(context, node_id, fn_inst_id, {width_id});
+  auto type_inst_id =
+      MakeFloatTypeLiteral(context, node_id, SemIR::FloatKind::None, size_id);
   context.node_stack().Push(node_id, type_inst_id);
   return true;
 }

+ 9 - 0
toolchain/check/import_cpp.cpp

@@ -794,6 +794,15 @@ static auto MapBuiltinType(Context& context, clang::QualType qual_type,
       return MakeIntType(context, context.ints().Add(width), is_signed);
     }
     // TODO: Handle integer types that map to named aliases.
+  } else if (type.isDoubleType()) {
+    // TODO: Handle other floating point types when Carbon supports fN where N
+    // != 64.
+    CARBON_CHECK(ast_context.getTypeSize(qual_type) == 64);
+    CARBON_CHECK(ast_context.hasSameType(qual_type, ast_context.DoubleTy));
+    return ExprAsType(
+        context, Parse::NodeId::None,
+        MakeFloatTypeLiteral(context, Parse::NodeId::None,
+                             SemIR::FloatKind::None, context.ints().Add(64)));
   }
 
   return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};

+ 10 - 0
toolchain/check/literal.cpp

@@ -9,6 +9,7 @@
 #include "toolchain/check/convert.h"
 #include "toolchain/check/name_lookup.h"
 #include "toolchain/check/type.h"
+#include "toolchain/sem_ir/ids.h"
 
 namespace Carbon::Check {
 
@@ -35,4 +36,13 @@ auto MakeIntType(Context& context, Parse::NodeId node_id,
   return ExprAsType(context, node_id, type_inst_id).type_id;
 }
 
+auto MakeFloatTypeLiteral(Context& context, Parse::NodeId node_id,
+                          SemIR::FloatKind float_kind, IntId size_id)
+    -> SemIR::InstId {
+  CARBON_CHECK(float_kind == SemIR::FloatKind::None);
+  auto width_id = MakeIntLiteral(context, node_id, size_id);
+  auto fn_inst_id = LookupNameInCore(context, node_id, "Float");
+  return PerformCall(context, node_id, fn_inst_id, {width_id});
+}
+
 }  // namespace Carbon::Check

+ 5 - 0
toolchain/check/literal.h

@@ -24,6 +24,11 @@ auto MakeIntTypeLiteral(Context& context, Parse::NodeId node_id,
 auto MakeIntType(Context& context, Parse::NodeId node_id,
                  SemIR::IntKind int_kind, IntId size_id) -> SemIR::TypeId;
 
+// Forms a floating point type expression for `fN` literal.
+auto MakeFloatTypeLiteral(Context& context, Parse::NodeId node_id,
+                          SemIR::FloatKind float_kind, IntId size_id)
+    -> SemIR::InstId;
+
 }  // namespace Carbon::Check
 
 #endif  // CARBON_TOOLCHAIN_CHECK_LITERAL_H_

+ 90 - 16
toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon

@@ -358,6 +358,26 @@ fn F() {
   //@dump-sem-ir-end
 }
 
+// ============================================================================
+// double param
+// ============================================================================
+
+// --- double_param.h
+
+auto foo(double a) -> void;
+
+// --- import_double_param.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp library "double_param.h";
+
+fn F() {
+  //@dump-sem-ir-begin
+  Cpp.foo(0.8 as f64);
+  //@dump-sem-ir-end
+}
+
 // ============================================================================
 // bool return
 // ============================================================================
@@ -399,29 +419,22 @@ fn F() {
 }
 
 // ============================================================================
-// float return
+// double return
 // ============================================================================
 
-// --- float_return.h
+// --- double_return.h
 
-auto foo_float() -> float;
+auto foo_double() -> double;
 
-// --- fail_todo_import_float_return.carbon
+// --- import_double_return.carbon
 
 library "[[@TEST_NAME]]";
 
-import Cpp library "float_return.h";
+import Cpp library "double_return.h";
 
 fn F() {
   //@dump-sem-ir-begin
-  // CHECK:STDERR: fail_todo_import_float_return.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: float` [SemanticsTodo]
-  // CHECK:STDERR:   Cpp.foo_float();
-  // CHECK:STDERR:   ^~~~~~~~~~~~~
-  // CHECK:STDERR: fail_todo_import_float_return.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo_float` [InCppNameLookup]
-  // CHECK:STDERR:   Cpp.foo_float();
-  // CHECK:STDERR:   ^~~~~~~~~~~~~
-  // CHECK:STDERR:
-  Cpp.foo_float();
+  let x: f64 = Cpp.foo_double();
   //@dump-sem-ir-end
 }
 
@@ -1074,6 +1087,43 @@ fn F() {
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: --- import_double_param.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %int_64: Core.IntLiteral = int_value 64 [concrete]
+// CHECK:STDOUT:   %Float.type: type = fn_type @Float [concrete]
+// CHECK:STDOUT:   %Float: %Float.type = struct_value () [concrete]
+// CHECK:STDOUT:   %foo.type: type = fn_type @foo [concrete]
+// CHECK:STDOUT:   %foo: %foo.type = struct_value () [concrete]
+// CHECK:STDOUT:   %float: f64 = float_literal 0.80000000000000004 [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
+// CHECK:STDOUT:     .foo = %foo.decl
+// CHECK:STDOUT:     import Cpp//...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
+// CHECK:STDOUT:   %float: f64 = float_literal 0.80000000000000004 [concrete = constants.%float]
+// CHECK:STDOUT:   %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
+// CHECK:STDOUT:   %Float.call: init type = call constants.%Float(%int_64) [concrete = f64]
+// CHECK:STDOUT:   %.loc8_18.1: type = value_of_initializer %Float.call [concrete = f64]
+// CHECK:STDOUT:   %.loc8_18.2: type = converted %Float.call, %.loc8_18.1 [concrete = f64]
+// CHECK:STDOUT:   %foo.call: init %empty_tuple.type = call %foo.ref(%float)
+// CHECK:STDOUT:   <elided>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- import_bool_return.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -1155,22 +1205,46 @@ fn F() {
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_import_float_return.carbon
+// CHECK:STDOUT: --- import_double_return.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %int_64: Core.IntLiteral = int_value 64 [concrete]
+// CHECK:STDOUT:   %Float.type: type = fn_type @Float [concrete]
+// CHECK:STDOUT:   %Float: %Float.type = struct_value () [concrete]
+// CHECK:STDOUT:   %pattern_type.3de: type = pattern_type f64 [concrete]
+// CHECK:STDOUT:   %foo_double.type: type = fn_type @foo_double [concrete]
+// CHECK:STDOUT:   %foo_double: %foo_double.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
-// CHECK:STDOUT:     .foo_float = <error>
+// CHECK:STDOUT:     .foo_double = %foo_double.decl
 // CHECK:STDOUT:     import Cpp//...
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %foo_double.decl: %foo_double.type = fn_decl @foo_double [concrete = constants.%foo_double] {
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() {
 // CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   name_binding_decl {
+// CHECK:STDOUT:     %x.patt: %pattern_type.3de = binding_pattern x [concrete]
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:   %foo_float.ref: <error> = name_ref foo_float, <error> [concrete = <error>]
+// CHECK:STDOUT:   %foo_double.ref: %foo_double.type = name_ref foo_double, imports.%foo_double.decl [concrete = constants.%foo_double]
+// CHECK:STDOUT:   %foo_double.call: init f64 = call %foo_double.ref()
+// CHECK:STDOUT:   %.loc8_10.1: type = splice_block %.loc8_10.3 [concrete = f64] {
+// CHECK:STDOUT:     %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
+// CHECK:STDOUT:     %Float.call: init type = call constants.%Float(%int_64) [concrete = f64]
+// CHECK:STDOUT:     %.loc8_10.2: type = value_of_initializer %Float.call [concrete = f64]
+// CHECK:STDOUT:     %.loc8_10.3: type = converted %Float.call, %.loc8_10.2 [concrete = f64]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc8_31.1: f64 = value_of_initializer %foo_double.call
+// CHECK:STDOUT:   %.loc8_31.2: f64 = converted %foo_double.call, %.loc8_31.1
+// CHECK:STDOUT:   %x: f64 = bind_name x, %.loc8_31.2
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT: