From 77804e938a3efb43dbaffad84ecef688ec196e1a Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 19 Sep 2025 19:43:47 +0000 Subject: [PATCH] Create Clang type sugar matching Carbon type names. --- toolchain/check/BUILD | 1 + toolchain/check/cpp/type_mapping.cpp | 26 ++++++++++++++++++- .../interop/cpp/function/operators.carbon | 4 +-- .../interop/cpp/function/reference.carbon | 10 +++---- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 607db96da212a..d6d7b64e11a96 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -155,6 +155,7 @@ cc_library( "//toolchain/sem_ir:expr_info", "//toolchain/sem_ir:file", "//toolchain/sem_ir:formatter", + "//toolchain/sem_ir:stringify", "//toolchain/sem_ir:typed_insts", "@llvm-project//clang:ast", "@llvm-project//clang:basic", diff --git a/toolchain/check/cpp/type_mapping.cpp b/toolchain/check/cpp/type_mapping.cpp index d7633833f26ce..1463125f790ff 100644 --- a/toolchain/check/cpp/type_mapping.cpp +++ b/toolchain/check/cpp/type_mapping.cpp @@ -22,6 +22,7 @@ #include "toolchain/sem_ir/expr_info.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" +#include "toolchain/sem_ir/stringify.h" #include "toolchain/sem_ir/type.h" #include "toolchain/sem_ir/type_info.h" #include "toolchain/sem_ir/typed_insts.h" @@ -229,6 +230,29 @@ static auto MapToCppType(Context& context, SemIR::InstId inst_id) return mapped_type; } +// Maps the type of a given Carbon instruction to a C++ type. Adds type sugar so +// the type prints the same as the Carbon type. +static auto MapToPrettyCppType(Context& context, SemIR::InstId inst_id) + -> clang::QualType { + auto type = MapToCppType(context, inst_id); + if (type.isNull()) { + return clang::QualType(); + } + + auto type_inst_id = + context.types().GetInstId(context.insts().Get(inst_id).type_id()); + auto type_name = SemIR::StringifyConstantInst(context.sem_ir(), type_inst_id); + + // TODO: Cache these and only create them once per type! + auto& ast = context.ast_context(); + auto* typedef_decl = clang::TypedefDecl::Create( + ast, ast.getTranslationUnitDecl(), clang::SourceLocation(), + clang::SourceLocation(), &ast.Idents.get(type_name), + ast.getTrivialTypeSourceInfo(type)); + return ast.getTypedefType(clang::ElaboratedTypeKeyword::None, std::nullopt, + typedef_decl); +} + auto InventClangArg(Context& context, SemIR::InstId arg_id) -> clang::Expr* { clang::ExprValueKind value_kind; switch (SemIR::GetExprCategory(context.sem_ir(), arg_id)) { @@ -262,7 +286,7 @@ auto InventClangArg(Context& context, SemIR::InstId arg_id) -> clang::Expr* { return nullptr; } - clang::QualType arg_cpp_type = MapToCppType(context, arg_id); + clang::QualType arg_cpp_type = MapToPrettyCppType(context, arg_id); if (arg_cpp_type.isNull()) { CARBON_DIAGNOSTIC(CppCallArgTypeNotSupported, Error, "call argument of type {0} is not supported", diff --git a/toolchain/check/testdata/interop/cpp/function/operators.carbon b/toolchain/check/testdata/interop/cpp/function/operators.carbon index e42e78f46e771..663db27dad97c 100644 --- a/toolchain/check/testdata/interop/cpp/function/operators.carbon +++ b/toolchain/check/testdata/interop/cpp/function/operators.carbon @@ -234,7 +234,7 @@ fn F() { // CHECK:STDERR: 16 | let c2: Cpp.C = c1 + 5; // CHECK:STDERR: | ^ // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./binary_operators.h:5:6: note: candidate function not viable: no known conversion from 'int' to 'C' for 2nd argument [CppInteropParseNote] + // CHECK:STDERR: ./binary_operators.h:5:6: note: candidate function not viable: no known conversion from 'Core.IntLiteral' (aka 'int') to 'C' for 2nd argument [CppInteropParseNote] // CHECK:STDERR: 5 | auto operator+(C lhs, C rhs) -> C; // CHECK:STDERR: | ^ ~~~~~ // CHECK:STDERR: @@ -243,7 +243,7 @@ fn F() { // CHECK:STDERR: 25 | let c3: Cpp.C = 6 + c1; // CHECK:STDERR: | ^ // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE-16]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./binary_operators.h:5:6: note: candidate function not viable: no known conversion from 'int' to 'C' for 1st argument [CppInteropParseNote] + // CHECK:STDERR: ./binary_operators.h:5:6: note: candidate function not viable: no known conversion from 'Core.IntLiteral' (aka 'int') to 'C' for 1st argument [CppInteropParseNote] // CHECK:STDERR: 5 | auto operator+(C lhs, C rhs) -> C; // CHECK:STDERR: | ^ ~~~~~ // CHECK:STDERR: diff --git a/toolchain/check/testdata/interop/cpp/function/reference.carbon b/toolchain/check/testdata/interop/cpp/function/reference.carbon index c5ef90ff75827..70fb151479490 100644 --- a/toolchain/check/testdata/interop/cpp/function/reference.carbon +++ b/toolchain/check/testdata/interop/cpp/function/reference.carbon @@ -59,7 +59,7 @@ fn F() { // CHECK:STDERR: 29 | Cpp.TakesLValue(t); // CHECK:STDERR: | ^ // CHECK:STDERR: fail_lvalue_ref.carbon:[[@LINE-20]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./lvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'T' to 'S &' for 1st argument [CppInteropParseNote] + // CHECK:STDERR: ./lvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'Cpp.T' (aka 'T') to 'S &' for 1st argument [CppInteropParseNote] // CHECK:STDERR: 5 | auto TakesLValue(S&) -> void; // CHECK:STDERR: | ^ ~~ // CHECK:STDERR: @@ -70,7 +70,7 @@ fn F() { // CHECK:STDERR: 40 | Cpp.TakesLValue(u as const Cpp.S); // CHECK:STDERR: | ^ // CHECK:STDERR: fail_lvalue_ref.carbon:[[@LINE-31]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./lvalue_ref.h:5:6: note: candidate function not viable: 1st argument ('const S') would lose const qualifier [CppInteropParseNote] + // CHECK:STDERR: ./lvalue_ref.h:5:6: note: candidate function not viable: 1st argument ('const Cpp.S' (aka 'const S')) would lose const qualifier [CppInteropParseNote] // CHECK:STDERR: 5 | auto TakesLValue(S&) -> void; // CHECK:STDERR: | ^ ~~ // CHECK:STDERR: @@ -142,7 +142,7 @@ fn F() { // CHECK:STDERR: 28 | Cpp.TakesRValue(t); // CHECK:STDERR: | ^ // CHECK:STDERR: fail_rvalue_ref.carbon:[[@LINE-19]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./rvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'T' to 'S' for 1st argument [CppInteropParseNote] + // CHECK:STDERR: ./rvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'Cpp.T' (aka 'T') to 'S' for 1st argument [CppInteropParseNote] // CHECK:STDERR: 5 | auto TakesRValue(S&&) -> void; // CHECK:STDERR: | ^ ~~~ // CHECK:STDERR: @@ -152,7 +152,7 @@ fn F() { // CHECK:STDERR: 38 | Cpp.TakesRValue(({} as Cpp.S) as const Cpp.S); // CHECK:STDERR: | ^ // CHECK:STDERR: fail_rvalue_ref.carbon:[[@LINE-29]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./rvalue_ref.h:5:6: note: candidate function not viable: 1st argument ('const S') would lose const qualifier [CppInteropParseNote] + // CHECK:STDERR: ./rvalue_ref.h:5:6: note: candidate function not viable: 1st argument ('const Cpp.S' (aka 'const S')) would lose const qualifier [CppInteropParseNote] // CHECK:STDERR: 5 | auto TakesRValue(S&&) -> void; // CHECK:STDERR: | ^ ~~~ // CHECK:STDERR: @@ -211,7 +211,7 @@ fn F() { // CHECK:STDERR: 29 | Cpp.TakesConstLValue(t); // CHECK:STDERR: | ^ // CHECK:STDERR: fail_const_lvalue_ref.carbon:[[@LINE-20]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./const_lvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'T' to 'const S' for 1st argument [CppInteropParseNote] + // CHECK:STDERR: ./const_lvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'Cpp.T' (aka 'T') to 'const S' for 1st argument [CppInteropParseNote] // CHECK:STDERR: 5 | auto TakesConstLValue(const S&) -> void; // CHECK:STDERR: | ^ ~~~~~~~~ // CHECK:STDERR: