Refactor TryEvaluateMacroToConstant to simplify and dedup code (#6820)

For integral and float types, `TryEvaluateMacroToConstant` now calls
`MapAPValueToConstant` to directly convert from an APValue, rather than
converting the `APValue` to an expression and importing it with
`MapConstant`.

`MapConstant` is still used, but only for string literals and nullptrs.
Since it's only used by `TryEvaluateMacroToConstant`, moved it to
`macros.cpp` and removed the code for other types of expressions.
This commit is contained in:
Nicholas Bishop
2026-03-02 21:00:07 +00:00
committed by GitHub
parent 6359e3f550
commit 069c6f4447
5 changed files with 142 additions and 245 deletions
+46 -25
View File
@@ -9,18 +9,50 @@
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "common/check.h"
#include "toolchain/check/cpp/constant.h"
#include "toolchain/check/cpp/import.h"
#include "toolchain/check/literal.h"
namespace Carbon::Check {
// Maps a Clang literal expression to a Carbon constant.
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<clang::StringLiteral>(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);
return inst_id;
} else if (isa<clang::CXXNullPtrLiteralExpr>(expr)) {
auto type_id = ImportCppType(context, loc_id, expr->getType()).type_id;
return GetOrAddInst<SemIR::UninitializedValue>(context, SemIR::LocId::None,
{.type_id = type_id});
}
context.TODO(loc_id,
llvm::formatv("Unsupported: C++ constant expression type: '{0}'",
expr->getType().getAsString()));
return SemIR::ErrorInst::InstId;
}
auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
SemIR::NameId name_id,
clang::MacroInfo* macro_info) -> clang::Expr* {
clang::MacroInfo* macro_info) -> SemIR::InstId {
auto name_str_opt = context.names().GetAsStringIfIdentifier(name_id);
CARBON_CHECK(macro_info, "macro info missing");
if (macro_info->getNumTokens() == 0) {
context.TODO(loc_id, "Unsupported: macro with 0 replacement tokens");
return nullptr;
return SemIR::ErrorInst::InstId;
}
clang::Sema& sema = context.clang_sema();
@@ -59,15 +91,14 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
"failed to parse macro Cpp.{0} to a valid constant expression",
std::string);
context.emitter().Emit(loc_id, InCppMacroEvaluation, (*name_str_opt).str());
return nullptr;
return SemIR::ErrorInst::InstId;
}
result_expr = result_expr->IgnoreParenImpCasts();
if (isa<clang::StringLiteral>(result_expr) ||
isa<clang::CharacterLiteral>(result_expr) ||
isa<clang::CXXNullPtrLiteralExpr>(result_expr)) {
return result_expr;
return MapConstant(context, loc_id, result_expr);
}
clang::Expr::EvalResult evaluated_result;
@@ -80,31 +111,21 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
if (!result_expr->EvaluateAsInt(evaluated_result, sema.getASTContext())) {
context.TODO(loc_id,
"Unsupported: macro evaluated to a non-integer LValue");
return nullptr;
return SemIR::ErrorInst::InstId;
}
ap_value = evaluated_result.Val;
}
switch (ap_value.getKind()) {
case clang::APValue::Int:
if (result_expr->getType()->isBooleanType()) {
return clang::CXXBoolLiteralExpr::Create(
sema.getASTContext(), ap_value.getInt().getBoolValue(),
result_expr->getType(), result_expr->getExprLoc());
}
return clang::IntegerLiteral::Create(
sema.getASTContext(), ap_value.getInt(), result_expr->getType(),
result_expr->getExprLoc());
case clang::APValue::Float:
return clang::FloatingLiteral::Create(
sema.getASTContext(), ap_value.getFloat(),
/*isExact=*/true, result_expr->getType(), result_expr->getExprLoc());
default:
context.TODO(loc_id,
"Unsupported: macro evaluated to a constant of type: " +
result_expr->getType().getAsString());
return nullptr;
auto const_id =
MapAPValueToConstant(context, loc_id, ap_value, result_expr->getType());
if (const_id == SemIR::ConstantId::NotConstant) {
context.TODO(loc_id,
"Unsupported: macro evaluated to a constant of type: " +
result_expr->getType().getAsString());
return SemIR::ErrorInst::InstId;
}
return context.constant_values().GetInstId(const_id);
}
} // namespace Carbon::Check