mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 07:11:04 +01:00
Add support for more complex object-like macros (#6338)
Uses `clang::Parser::ParseConstantExpression()` to parse the macro replacement tokens, added as a token stream to the preprocessor. This extends the support from simple object-like macros with a single replacement token, to multiple tokens like unary operators, binary operators, casting, nested macros etc. The support is still limited to macros that are evaluated to an integer constant. More types to be added as a follow-up. Part of #6303
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
#include "toolchain/check/cpp/macros.h"
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
@@ -14,24 +16,41 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
|
||||
clang::MacroInfo* macro_info) -> clang::Expr* {
|
||||
auto name_str_opt = context.names().GetAsStringIfIdentifier(name_id);
|
||||
CARBON_CHECK(macro_info, "macro info missing");
|
||||
if (macro_info->getNumTokens() != 1) {
|
||||
context.TODO(loc_id,
|
||||
llvm::formatv("Unsupported: macro with {0} replacement tokens",
|
||||
macro_info->getNumTokens()));
|
||||
return nullptr;
|
||||
}
|
||||
const clang::Token& tok = macro_info->getReplacementToken(0);
|
||||
if (!tok.is(clang::tok::numeric_constant)) {
|
||||
context.TODO(loc_id,
|
||||
"Unsupported: macro replacement token kind: " +
|
||||
std::string(clang::tok::getTokenName(tok.getKind())));
|
||||
|
||||
if (macro_info->getNumTokens() == 0) {
|
||||
context.TODO(loc_id, "Unsupported: macro with 0 replacement tokens");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
clang::ExprResult result = sema.ActOnNumericConstant(tok);
|
||||
clang::Preprocessor& preprocessor = sema.getPreprocessor();
|
||||
clang::Parser parser(preprocessor, sema, false);
|
||||
|
||||
llvm::SmallVector<clang::Token> tokens(macro_info->tokens().begin(),
|
||||
macro_info->tokens().end());
|
||||
|
||||
clang::Token current_token = parser.getCurToken();
|
||||
|
||||
// Add eof token
|
||||
clang::Token eof;
|
||||
eof.startToken();
|
||||
eof.setKind(clang::tok::eof);
|
||||
eof.setLocation(current_token.getEndLoc());
|
||||
tokens.push_back(eof);
|
||||
|
||||
tokens.push_back(current_token);
|
||||
|
||||
preprocessor.EnterTokenStream(tokens, false, false);
|
||||
parser.ConsumeAnyToken(true);
|
||||
|
||||
clang::ExprResult result = parser.ParseConstantExpression();
|
||||
clang::Expr* result_expr = result.get();
|
||||
|
||||
if (!result_expr || result.isInvalid()) {
|
||||
bool success =
|
||||
!result.isInvalid() && parser.getCurToken().is(clang::tok::eof);
|
||||
|
||||
if (!success) {
|
||||
parser.SkipUntil(clang::tok::eof);
|
||||
CARBON_DIAGNOSTIC(
|
||||
InCppMacroEvaluation, Error,
|
||||
"failed to evaluate macro Cpp.{0} to a valid constant expression",
|
||||
@@ -40,7 +59,14 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result_expr;
|
||||
clang::Expr::EvalResult evaluated_result;
|
||||
if (!result_expr->EvaluateAsInt(evaluated_result, sema.getASTContext())) {
|
||||
context.TODO(loc_id, "non-integer constant expression in macro.");
|
||||
return nullptr;
|
||||
}
|
||||
return clang::IntegerLiteral::Create(
|
||||
sema.getASTContext(), evaluated_result.Val.getInt(),
|
||||
result_expr->getType(), result_expr->getExprLoc());
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
Reference in New Issue
Block a user