diff --git a/toolchain/check/cpp/generate_ast.cpp b/toolchain/check/cpp/generate_ast.cpp index f24117caf135..322c99f37a69 100644 --- a/toolchain/check/cpp/generate_ast.cpp +++ b/toolchain/check/cpp/generate_ast.cpp @@ -389,6 +389,48 @@ auto CarbonExternalASTSource::MapInstIdToClangDecl( *ast_context_, clang::TagTypeKind::Class, &decl_context, clang::SourceLocation(), clang::SourceLocation(), identifier_info); } + case SemIR::StructValue::Kind: { + auto callee = GetCallee(context_->sem_ir(), target_constant); + auto* callee_function = std::get_if(&callee); + if (!callee_function) { + return nullptr; + } + const SemIR::Function& function = + context_->functions().Get(callee_function->function_id); + auto* identifier_info = + GetClangIdentifierInfo(*context_, function.name_id); + + if (function.call_param_ranges.explicit_size() != 0) { + context_->TODO(target_inst_id, + "unsupported: C++ calling a Carbon function with " + "parameters"); + return nullptr; + } + + if (function.return_type_inst_id != SemIR::TypeInstId::None) { + context_->TODO(target_inst_id, + "unsupported: C++ calling a Carbon function with " + "return type other than `()`"); + return nullptr; + } + + // TODO: support non-empty parameter lists. + llvm::SmallVector cpp_param_types; + + // TODO: support non-void return types. + auto cpp_return_type = ast_context_->VoidTy; + + auto cpp_function_type = ast_context_->getFunctionType( + cpp_return_type, cpp_param_types, + clang::FunctionProtoType::ExtProtoInfo()); + + return clang::FunctionDecl::Create( + *ast_context_, &decl_context, + /*StartLoc=*/clang::SourceLocation(), + /*NLoc=*/clang::SourceLocation(), + clang::DeclarationName(identifier_info), cpp_function_type, + /*TInfo=*/nullptr, clang::SC_Extern); + } default: return nullptr; } diff --git a/toolchain/check/testdata/interop/cpp/reverse/function.carbon b/toolchain/check/testdata/interop/cpp/reverse/function.carbon new file mode 100644 index 000000000000..cb091138d35a --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/reverse/function.carbon @@ -0,0 +1,69 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/reverse/function.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/reverse/function.carbon + +// --- other.carbon + +package Other; +fn F1() {} +fn F2() -> i32 { return 0; } +fn F3(_: i32) {} + +// --- function.carbon + +library "[[@TEST_NAME]]"; + +import Other; +import Cpp inline ''' +void G() { + Carbon::Other::F1(); +} +'''; + +// --- fail_todo_non_void.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_todo_non_void.carbon:[[@LINE+5]]:1: in import [InImport] +// CHECK:STDERR: other.carbon:4:1: error: semantics TODO: `unsupported: C++ calling a Carbon function with return type other than `()`` [SemanticsTodo] +// CHECK:STDERR: fn F2() -> i32 { return 0; } +// CHECK:STDERR: ^~~~~~~~~~~~~~~~ +// CHECK:STDERR: +import Other; +import Cpp inline ''' +void G() { + // CHECK:STDERR: fail_todo_non_void.carbon:[[@LINE+4]]:18: error: no member named 'F2' in namespace 'Carbon::Other' [CppInteropParseError] + // CHECK:STDERR: 16 | Carbon::Other::F2(); + // CHECK:STDERR: | ^~ + // CHECK:STDERR: + Carbon::Other::F2(); +} +'''; + +// --- fail_todo_args.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_todo_args.carbon:[[@LINE+5]]:1: in import [InImport] +// CHECK:STDERR: other.carbon:5:1: error: semantics TODO: `unsupported: C++ calling a Carbon function with parameters` [SemanticsTodo] +// CHECK:STDERR: fn F3(_: i32) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~ +// CHECK:STDERR: +import Other; +import Cpp inline ''' +void G() { + // CHECK:STDERR: fail_todo_args.carbon:[[@LINE+4]]:18: error: no member named 'F3' in namespace 'Carbon::Other' [CppInteropParseError] + // CHECK:STDERR: 16 | Carbon::Other::F3(); + // CHECK:STDERR: | ^~ + // CHECK:STDERR: + Carbon::Other::F3(); +} +'''; diff --git a/toolchain/lower/testdata/interop/cpp/reverse/function.carbon b/toolchain/lower/testdata/interop/cpp/reverse/function.carbon new file mode 100644 index 000000000000..d7c3d6b482e7 --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/reverse/function.carbon @@ -0,0 +1,84 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/reverse/function.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/reverse/function.carbon + +// --- other.carbon +package Other; +fn F() {} +// --- function.carbon + +library "[[@TEST_NAME]]"; + +import Other; +import Cpp inline ''' +void G() { + // TODO: this is not actually calling the Carbon function yet, because + // it's not using the right mangled name. + Carbon::Other::F(); +} +'''; + +// CHECK:STDOUT: ; ModuleID = 'other.carbon' +// CHECK:STDOUT: source_filename = "other.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF.Other() #0 !dbg !4 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !7 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} +// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !3 = !DIFile(filename: "other.carbon", directory: "") +// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "F", linkageName: "_CF.Other", scope: null, file: !3, line: 2, type: !5, spFlags: DISPFlagDefinition, unit: !2) +// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !6 = !{null} +// CHECK:STDOUT: !7 = !DILocation(line: 2, column: 1, scope: !4) +// CHECK:STDOUT: ; ModuleID = 'function.carbon' +// CHECK:STDOUT: source_filename = "function.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable +// CHECK:STDOUT: define dso_local void @_Z1Gv() #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_ZN6Carbon5Other1FEv() +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_ZN6Carbon5Other1FEv() #1 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_CF.Other() +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "function.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!8, !8, i64 0} +// CHECK:STDOUT: !8 = !{!"int", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"}