From 8866e39085a1d36a66abf83ff9b07c5d3f27c48e Mon Sep 17 00:00:00 2001 From: Ivana Ivanovska Date: Fri, 21 Nov 2025 13:33:18 +0100 Subject: [PATCH] Add support for string literals in macros (#6408) Adding support for macros with string literals. Part of #6303 --- toolchain/check/cpp/import.cpp | 15 +++ toolchain/check/cpp/macros.cpp | 4 + .../check/testdata/interop/cpp/macros.carbon | 107 +++++++++++++++--- 3 files changed, 111 insertions(+), 15 deletions(-) diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index dcd8bf4e911b..7f7135429015 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -2234,6 +2234,21 @@ static auto MapConstant(Context& context, SemIR::LocId loc_id, clang::Expr* expr) -> SemIR::InstId { CARBON_CHECK(expr, "empty expression"); + if (auto* string_literal = dyn_cast(expr)) { + if (!string_literal->isOrdinary() && !string_literal->isUTF8()) { + context.TODO(loc_id, + llvm::formatv("Unsupported: string literal type: {0}", + expr->getType())); + return SemIR::ErrorInst::InstId; + } + StringLiteralValueId string_id = + context.string_literal_values().Add(string_literal->getString()); + auto inst_id = + MakeStringLiteral(context, Parse::StringLiteralId::None, string_id); + context.imports().push_back(inst_id); + return inst_id; + } + SemIR::TypeId type_id = MapType(context, loc_id, expr->getType()).type_id; if (!type_id.has_value()) { context.TODO(loc_id, llvm::formatv("Unsupported: C++ literal's type `{0}` " diff --git a/toolchain/check/cpp/macros.cpp b/toolchain/check/cpp/macros.cpp index 8201bd09574f..c3ca2e66f8de 100644 --- a/toolchain/check/cpp/macros.cpp +++ b/toolchain/check/cpp/macros.cpp @@ -61,6 +61,10 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id, return nullptr; } + if (isa(result_expr)) { + return result_expr; + } + clang::Expr::EvalResult evaluated_result; CARBON_CHECK(result_expr->EvaluateAsConstantExpr(evaluated_result, sema.getASTContext())); diff --git a/toolchain/check/testdata/interop/cpp/macros.carbon b/toolchain/check/testdata/interop/cpp/macros.carbon index 241d17da25e1..0b3f41e954a9 100644 --- a/toolchain/check/testdata/interop/cpp/macros.carbon +++ b/toolchain/check/testdata/interop/cpp/macros.carbon @@ -254,28 +254,105 @@ fn F() { } // --- string_literal_object_like_macro.h -#define CONFIG_VALUE "abc" -// --- fail_todo_import_string_literal_object_like_macro.carbon +#define SimpleString "abc" +#define EmptyString "" +#define EscapeCharacter " \t " +#define Concatenated "a" "b" +#define RawString R"a( foo: "bar" { 123 } )a" +#define Utf8String u8"абв" + +#define CONCAT_STR(A, B) #A #B +#define Indirect CONCAT_STR(x, y) + +// --- import_string_literal_object_like_macro.carbon library "[[@TEST_NAME]]"; import Cpp library "string_literal_object_like_macro.h"; fn F() { - // TODO: Get rid of the second error. - // CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+11]]:3: error: semantics TODO: `Unsupported: macro evaluated to a constant of type: const char[4]` [SemanticsTodo] - // CHECK:STDERR: Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `CONFIG_VALUE` [InCppNameLookup] - // CHECK:STDERR: Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_string_literal_object_like_macro.carbon:[[@LINE+4]]:3: error: member name `CONFIG_VALUE` not found in `Cpp` [MemberNameNotFoundInInstScope] - // CHECK:STDERR: Cpp.CONFIG_VALUE; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: - Cpp.CONFIG_VALUE; + let a: str = Cpp.SimpleString; + let b: str = Cpp.EmptyString; + let c: str = Cpp.EscapeCharacter; + let d: str = Cpp.Concatenated; + let e: str = Cpp.RawString; + let f: str = Cpp.Utf8String; + let g: str = Cpp.Indirect; +} + +// --- unsupported_string_literal_types.h + +#define Utf16Greeting u"Hello" +#define Utf32Greeting U"Hello" +#define WideGreeting L"Hello" + +// --- fail_import_unsupported_string_literal_types.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "unsupported_string_literal_types.h"; + +fn F() { + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+11]]:2: error: semantics TODO: `Unsupported: string literal type: const char16_t[6]` [SemanticsTodo] + // CHECK:STDERR: Cpp.Utf16Greeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+8]]:2: note: in `Cpp` name lookup for `Utf16Greeting` [InCppNameLookup] + // CHECK:STDERR: Cpp.Utf16Greeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+4]]:2: error: member name `Utf16Greeting` not found in `Cpp` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: Cpp.Utf16Greeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.Utf16Greeting; + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+11]]:2: error: semantics TODO: `Unsupported: string literal type: const char32_t[6]` [SemanticsTodo] + // CHECK:STDERR: Cpp.Utf32Greeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+8]]:2: note: in `Cpp` name lookup for `Utf32Greeting` [InCppNameLookup] + // CHECK:STDERR: Cpp.Utf32Greeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+4]]:2: error: member name `Utf32Greeting` not found in `Cpp` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: Cpp.Utf32Greeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.Utf32Greeting; + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+11]]:2: error: semantics TODO: `Unsupported: string literal type: const wchar_t[6]` [SemanticsTodo] + // CHECK:STDERR: Cpp.WideGreeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+8]]:2: note: in `Cpp` name lookup for `WideGreeting` [InCppNameLookup] + // CHECK:STDERR: Cpp.WideGreeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_unsupported_string_literal_types.carbon:[[@LINE+4]]:2: error: member name `WideGreeting` not found in `Cpp` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: Cpp.WideGreeting; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.WideGreeting; +} + +// --- fail_bad_string.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline ''' + #define BadString "123" 456 +'''; + +fn F() { + // CHECK:STDERR: fail_bad_string.carbon:[[@LINE+11]]:2: error: failed to parse macro Cpp.BadString to a valid constant expression [InCppMacroEvaluation] + // CHECK:STDERR: Cpp.BadString; + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: fail_bad_string.carbon:[[@LINE+8]]:2: note: in `Cpp` name lookup for `BadString` [InCppNameLookup] + // CHECK:STDERR: Cpp.BadString; + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_bad_string.carbon:[[@LINE+4]]:2: error: member name `BadString` not found in `Cpp` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: Cpp.BadString; + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.BadString; } // --- floating_point_literal_macro.h