From 047555bb1cc8f2c88b7deb81880ea69d0ae7acd0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 19 Aug 2026 00:47:03 +0000 Subject: [PATCH] Don't crash if a macro expands to an erroneous expression. (#7652) For certain kinds of error, clang's parser will succeed but produce an expression marked as "contains error". Clang's constant evaluator asserts if given one of those, so return early if we encounter one. --- toolchain/check/cpp/macros.cpp | 2 +- .../interop/cpp/macros/invalid.carbon | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 toolchain/check/testdata/interop/cpp/macros/invalid.carbon diff --git a/toolchain/check/cpp/macros.cpp b/toolchain/check/cpp/macros.cpp index a344e21fd0a8..20005e05c423 100644 --- a/toolchain/check/cpp/macros.cpp +++ b/toolchain/check/cpp/macros.cpp @@ -84,7 +84,7 @@ auto TryEvaluateMacro(Context& context, SemIR::LocId loc_id, parser.ConsumeAnyToken(true); } - if (!success) { + if (!success || result_expr->containsErrors()) { CARBON_DIAGNOSTIC( InCppMacroEvaluation, Error, "failed to parse macro Cpp.{0} to a valid constant expression", diff --git a/toolchain/check/testdata/interop/cpp/macros/invalid.carbon b/toolchain/check/testdata/interop/cpp/macros/invalid.carbon new file mode 100644 index 000000000000..6792db395768 --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/macros/invalid.carbon @@ -0,0 +1,58 @@ +// 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/primitives.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/macros/invalid.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/macros/invalid.carbon + +// --- fail_macro_with_error.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline ''' +// CHECK:STDERR: fail_macro_with_error.carbon:[[@LINE+4]]:1: error: unknown type name 'error' [CppInteropParseError] +// CHECK:STDERR: 9 | error has_error; +// CHECK:STDERR: | ^ +// CHECK:STDERR: +error has_error; +#define macro_with_error has_error.member +'''; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_macro_with_error.carbon:[[@LINE+11]]:3: error: failed to parse macro Cpp.macro_with_error to a valid constant expression [InCppMacroEvaluation] + // CHECK:STDERR: Cpp.macro_with_error; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_macro_with_error.carbon:[[@LINE+8]]:3: note: in `Cpp` name lookup for `macro_with_error` [InCppNameLookup] + // CHECK:STDERR: Cpp.macro_with_error; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_macro_with_error.carbon:[[@LINE+4]]:3: error: member name `macro_with_error` not found in `Cpp` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: Cpp.macro_with_error; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.macro_with_error; + //@dump-sem-ir-end +} + +// CHECK:STDOUT: --- fail_macro_with_error.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .macro_with_error = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %macro_with_error.ref: = name_ref macro_with_error, [concrete = ] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: