[clang] [CIR][NFC] Add errors for unhandled AggExprEmitter visitors (PR #155469)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 27 12:12:58 PDT 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/155469
>From 711aee40c93a964cf8c731e1eb2aea4b1a055783 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Tue, 26 Aug 2025 09:36:52 -0700
Subject: [PATCH 1/2] [CIR][NFC] Add errors for unhandled AggExprEmitter
visitors
There are a lot of required handlers in AggExprEmitter that are currently
missing. Because the ASTVisitor has fallbacks, this means we just silently
ignore whatever expressions are not explicitly handled. This patch adds
handlers where we know they will be needed and just issues a diagnostic.
This exposed failures in a few tests. In one case, we should have handled
constant initialization earlier, which would have avoided going to
the AggExprEmitter at all. I added a stub with a missing feature marker
to allow that case to work as it had. Another test required us to
ignore cast expressions that should be ignored, so I partially implemented
the cast visitor. Finally, there's a case where the test was just
accepting a bad result. I changed that case to XFAIL until it can be
properly fixed.
---
clang/include/clang/CIR/MissingFeatures.h | 1 +
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 199 ++++++++++++++++++
clang/test/CIR/CodeGen/statement-exprs.c | 3 +
3 files changed, 203 insertions(+)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index d7a2e49ec162a..a8be2a2374d6e 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -195,6 +195,7 @@ struct MissingFeatures {
static bool cirgenABIInfo() { return false; }
static bool cleanupAfterErrorDiags() { return false; }
static bool cleanupsToDeactivate() { return false; }
+ static bool constEmitterAggILE() { return false; }
static bool constEmitterArrayILE() { return false; }
static bool constEmitterVectorILE() { return false; }
static bool constantFoldSwitchStatement() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index bab9ac73d7e65..113f9961d2b48 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -84,6 +84,205 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,
FieldDecl *initializedFieldInUnion,
Expr *arrayFiller);
+
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
+ assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
+ Visit(e->getSubExpr());
+ }
+
+ // Stubs -- These should be moved up when they are implemented.
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *e) {
+ // We shouldn't really get here, but we do because of missing handling for
+ // emitting constant aggregate initializers. If we just ignore this, a
+ // fallback handler will do the right thing.
+ assert(!cir::MissingFeatures::constEmitterAggILE());
+ return;
+ }
+ void VisitCastExpr(CastExpr *e) {
+ switch (e->getCastKind()) {
+ case CK_LValueToRValue:
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+ [[fallthrough]];
+ case CK_NoOp:
+ case CK_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ assert(cgf.getContext().hasSameUnqualifiedType(e->getSubExpr()->getType(),
+ e->getType()) &&
+ "Implicit cast types must be compatible");
+ Visit(e->getSubExpr());
+ break;
+ default:
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ std::string("AggExprEmitter: VisitCastExpr: ") +
+ e->getCastKindName());
+ break;
+ }
+ }
+ void VisitStmt(Stmt *s) {
+ cgf.cgm.errorNYI(s->getSourceRange(),
+ std::string("AggExprEmitter::VisitStmt: ") +
+ s->getStmtClassName());
+ }
+ void VisitParenExpr(ParenExpr *pe) {
+ cgf.cgm.errorNYI(pe->getSourceRange(), "AggExprEmitter: VisitParenExpr");
+ }
+ void VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
+ cgf.cgm.errorNYI(ge->getSourceRange(),
+ "AggExprEmitter: VisitGenericSelectionExpr");
+ }
+ void VisitCoawaitExpr(CoawaitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoawaitExpr");
+ }
+ void VisitCoyieldExpr(CoyieldExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoyieldExpr");
+ }
+ void VisitUnaryCoawait(UnaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryCoawait");
+ }
+ void VisitUnaryExtension(UnaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitUnaryExtension");
+ }
+ void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitSubstNonTypeTemplateParmExpr");
+ }
+ void VisitConstantExpr(ConstantExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr");
+ }
+ void VisitMemberExpr(MemberExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitMemberExpr");
+ }
+ void VisitUnaryDeref(UnaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryDeref");
+ }
+ void VisitStringLiteral(StringLiteral *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitStringLiteral");
+ }
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCompoundLiteralExpr");
+ }
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitArraySubscriptExpr");
+ }
+ void VisitPredefinedExpr(const PredefinedExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitPredefinedExpr");
+ }
+ void VisitBinaryOperator(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitBinaryOperator");
+ }
+ void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitPointerToDataMemberBinaryOperator");
+ }
+ void VisitBinAssign(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinAssign");
+ }
+ void VisitBinComma(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinComma");
+ }
+ void VisitBinCmp(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp");
+ }
+ void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXRewrittenBinaryOperator");
+ }
+ void VisitObjCMessageExpr(ObjCMessageExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitObjCMessageExpr");
+ }
+ void VisitObjCIVarRefExpr(ObjCIvarRefExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitObjCIVarRefExpr");
+ }
+
+ void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitDesignatedInitUpdateExpr");
+ }
+ void VisitAbstractConditionalOperator(const AbstractConditionalOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitAbstractConditionalOperator");
+ }
+ void VisitChooseExpr(const ChooseExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitChooseExpr");
+ }
+ void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXParenListInitExpr");
+ }
+ void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *e,
+ llvm::Value *outerBegin = nullptr) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitArrayInitLoopExpr");
+ }
+ void VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitImplicitValueInitExpr");
+ }
+ void VisitNoInitExpr(NoInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitNoInitExpr");
+ }
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
+ cgf.cgm.errorNYI(dae->getSourceRange(),
+ "AggExprEmitter: VisitCXXDefaultArgExpr");
+ }
+ void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
+ cgf.cgm.errorNYI(die->getSourceRange(),
+ "AggExprEmitter: VisitCXXDefaultInitExpr");
+ }
+ void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXInheritedCtorInitExpr");
+ }
+ void VisitLambdaExpr(LambdaExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitLambdaExpr");
+ }
+ void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXStdInitializerListExpr");
+ }
+
+ void VisitExprWithCleanups(ExprWithCleanups *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitExprWithCleanups");
+ }
+ void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXScalarValueInitExpr");
+ }
+ void VisitCXXTypeidExpr(CXXTypeidExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr");
+ }
+ void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitMaterializeTemporaryExpr");
+ }
+ void VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitOpaqueValueExpr");
+ }
+
+ void VisitPseudoObjectExpr(PseudoObjectExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitPseudoObjectExpr");
+ }
+
+ void VisitVAArgExpr(VAArgExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitVAArgExpr");
+ }
+
+ void VisitCXXThrowExpr(const CXXThrowExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXThrowExpr");
+ }
+ void VisitAtomicExpr(AtomicExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitAtomicExpr");
+ }
};
} // namespace
diff --git a/clang/test/CIR/CodeGen/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c
index 927a868336b59..1b54edfe7ec30 100644
--- a/clang/test/CIR/CodeGen/statement-exprs.c
+++ b/clang/test/CIR/CodeGen/statement-exprs.c
@@ -5,6 +5,9 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+// This fails because of a non-ignored copy of an aggregate in test3.
+// XFAIL: *
+
int f19(void) {
return ({ 3;;4;; });
}
>From b565367186c1034aa982d5e13274996f431c5b8a Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 27 Aug 2025 12:12:08 -0700
Subject: [PATCH 2/2] Update OpenACC firstprivate test after rebase
---
clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.c b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.c
index 58b84e05f4fb4..7f1480f212d73 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.c
+++ b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s
+// RUN: not %clang_cc1 -fopenacc -triple x86_64-linux-gnu -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple x86_64-linux-pc %s -o - | FileCheck %s
+
+// This encounters NYI errors because of a non-ignored copy of an aggregate.
+// When that is fixed, the 'not' should be removed from the RUN line above.
struct NoCopyConstruct {};
More information about the cfe-commits
mailing list