Przeglądaj źródła

Improve diagnostics for EvaluateAsConstantExpr (#6956)

Initialize the `Diag` field `EvalResult` to get notes from clang when
`EvaluateAsConstantExpr` fails, then emit them using clang's diagnostic
infrastructure.

Also set valid source locations in a couple places, otherwise clang's
diagnostics code crashes.
Nicholas Bishop 1 miesiąc temu
rodzic
commit
f9e1806c4a

+ 12 - 9
toolchain/check/cpp/constant.cpp

@@ -5,6 +5,7 @@
 #include "toolchain/check/cpp/constant.h"
 
 #include "toolchain/check/cpp/import.h"
+#include "toolchain/check/cpp/location.h"
 #include "toolchain/check/cpp/type_mapping.h"
 #include "toolchain/check/eval.h"
 #include "toolchain/check/member_access.h"
@@ -226,7 +227,7 @@ auto EvalCppCall(Context& context, SemIR::LocId loc_id,
       context.ast_context(), /*QualifierLoc=*/clang::NestedNameSpecifierLoc(),
       /*TemplateKWLoc=*/clang::SourceLocation(), function_decl,
       /*RefersToEnclosingVariableOrCapture=*/false,
-      /*NameLoc=*/clang::SourceLocation(), function_decl->getType(),
+      /*NameLoc=*/GetCppLocation(context, loc_id), function_decl->getType(),
       clang::VK_LValue);
 
   // Cast to a function pointer type.
@@ -253,18 +254,20 @@ auto EvalCppCall(Context& context, SemIR::LocId loc_id,
   auto* call_expr = clang::CallExpr::Create(
       context.ast_context(), implicit_cast_expr, arg_exprs,
       function_decl->getCallResultType(), clang::VK_PRValue,
-      /*RParenLoc=*/clang::SourceLocation(), clang::FPOptionsOverride());
+      /*RParenLoc=*/GetCppLocation(context, loc_id),
+      clang::FPOptionsOverride());
 
   // Evaluate the expr as a constant and map that to Carbon constant.
+  clang::SmallVector<clang::PartialDiagnosticAt> notes;
   clang::Expr::EvalResult eval_result;
+  eval_result.Diag = &notes;
   if (!call_expr->EvaluateAsConstantExpr(eval_result, context.ast_context())) {
-    // TODO: improve this diagnostic with information from `eval_result`.
-    CARBON_DIAGNOSTIC(CppConstexprEval, Error,
-                      "failed to evaluate {0:consteval|constexpr} function "
-                      "call as a constant",
-                      Diagnostics::BoolAsSelect);
-    context.emitter().Emit(loc_id, CppConstexprEval,
-                           function_decl->isConsteval());
+    context.clang_sema().Diag(call_expr->getBeginLoc(),
+                              clang::diag::err_invalid_consteval_call)
+        << function_decl << function_decl->isConsteval();
+    for (const auto& note : notes) {
+      context.clang_sema().Diag(note.first, note.second);
+    }
     return SemIR::ErrorInst::ConstantId;
   }
 

+ 9 - 3
toolchain/check/testdata/interop/cpp/constexpr.carbon

@@ -80,8 +80,14 @@ constexpr int f(int a) {
 }
 ''';
 
-// CHECK:STDERR: fail_invalid_constant_eval.carbon:[[@LINE+4]]:19: error: failed to evaluate constexpr function call as a constant [CppConstexprEval]
-// CHECK:STDERR: let a: array(i32, Cpp.f(5)) = (1, 2, 3);
-// CHECK:STDERR:                   ^~~~~~~~
+// CHECK:STDERR: fail_invalid_constant_eval.carbon:[[@LINE+10]]:26: error: call to immediate function 'f' is not a constant expression [CppInteropParseError]
+// CHECK:STDERR:    21 | let a: array(i32, Cpp.f(5)) = (1, 2, 3);
+// CHECK:STDERR:       |                          ^
+// CHECK:STDERR: fail_invalid_constant_eval.carbon:[[@LINE-7]]:10: note: cannot refer to element 5 of array of 1 element in a constant expression [CppInteropParseNote]
+// CHECK:STDERR:     7 |   return arr[a];
+// CHECK:STDERR:       |          ^
+// CHECK:STDERR: fail_invalid_constant_eval.carbon:[[@LINE+4]]:26: note: in call to 'f(5)' [CppInteropParseNote]
+// CHECK:STDERR:    21 | let a: array(i32, Cpp.f(5)) = (1, 2, 3);
+// CHECK:STDERR:       |                          ^
 // CHECK:STDERR:
 let a: array(i32, Cpp.f(5)) = (1, 2, 3);

+ 0 - 1
toolchain/diagnostics/kind.def

@@ -270,7 +270,6 @@ CARBON_DIAGNOSTIC_KIND(RefTagNoRefParam)
 CARBON_DIAGNOSTIC_KIND(RefTagNotDurableRef)
 CARBON_DIAGNOSTIC_KIND(SelfParameterNotAllowed)
 CARBON_DIAGNOSTIC_KIND(ValueForRefParam)
-CARBON_DIAGNOSTIC_KIND(CppConstexprEval)
 
 // Function declaration checking.
 CARBON_DIAGNOSTIC_KIND(DefinedAbstractFunction)