[clang] [CIR] Upstream namepsace handling (PR #137253)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 24 14:47:54 PDT 2025
https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/137253
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).
>From 8e8baed406019bee2b5acd71b0d08b65360ee032 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Thu, 17 Apr 2025 11:58:03 -0700
Subject: [PATCH] [CIR] Upstream namepsace handling
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which
is needed for anonymous namespaces).
---
clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 4 ++
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 20 ++++++++++
clang/lib/CIR/CodeGen/CIRGenModule.h | 3 ++
clang/test/CIR/CodeGen/namespace.cpp | 55 ++++++++++++++++++++++++++
4 files changed, 82 insertions(+)
create mode 100644 clang/test/CIR/CodeGen/namespace.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index d7cbb4f64b2ea..8026f22b00117 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -260,7 +260,11 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,
void CIRGenFunction::emitDecl(const Decl &d) {
switch (d.getKind()) {
+ case Decl::Namespace:
+ llvm_unreachable("Declaration should not be in declstmts!");
+
case Decl::Record: // struct/union/class X;
+ case Decl::UsingDirective: // using namespace X; [C++]
assert(!cir::MissingFeatures::generateDebugInfo());
return;
case Decl::Var: {
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0b266df13fd40..0f4193b5756fd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -621,6 +621,20 @@ CIRGenModule::getCIRLinkageVarDefinition(const VarDecl *vd, bool isConstant) {
return getCIRLinkageForDeclarator(vd, linkage, isConstant);
}
+void CIRGenModule::emitDeclContext(const DeclContext *dc) {
+ for (Decl *decl : dc->decls()) {
+ // Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope
+ // are themselves considered "top-level", so EmitTopLevelDecl on an
+ // ObjCImplDecl does not recursively visit them. We need to do that in
+ // case they're nested inside another construct (LinkageSpecDecl /
+ // ExportDecl) that does stop them from being considered "top-level".
+ if (auto *oid = dyn_cast<ObjCImplDecl>(decl))
+ errorNYI(oid->getSourceRange(), "emitDeclConext: ObjCImplDecl");
+
+ emitTopLevelDecl(decl);
+ }
+}
+
// Emit code for a single top level declaration.
void CIRGenModule::emitTopLevelDecl(Decl *decl) {
@@ -654,12 +668,18 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
emitGlobalOpenACCDecl(cast<OpenACCDeclareDecl>(decl));
break;
+ case Decl::UsingDirective: // using namespace X; [C++]
case Decl::Typedef:
case Decl::TypeAlias: // using foo = bar; [C++11]
case Decl::Record:
case Decl::CXXRecord:
assert(!cir::MissingFeatures::generateDebugInfo());
break;
+
+ // C++ Decls
+ case Decl::Namespace:
+ emitDeclContext(cast<NamespaceDecl>(decl));
+ break;
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 1c14959700cf9..ea30903a97167 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -170,6 +170,9 @@ class CIRGenModule : public CIRGenTypeCache {
void emitGlobalOpenACCDecl(const clang::OpenACCConstructDecl *cd);
+ // C++ related functions.
+ void emitDeclContext(const DeclContext *dc);
+
/// Return the result of value-initializing the given type, i.e. a null
/// expression of the given type.
mlir::Value emitNullConstant(QualType t, mlir::Location loc);
diff --git a/clang/test/CIR/CodeGen/namespace.cpp b/clang/test/CIR/CodeGen/namespace.cpp
new file mode 100644
index 0000000000000..cfeb17bd19ced
--- /dev/null
+++ b/clang/test/CIR/CodeGen/namespace.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s
+
+// Test anonymous namespace.
+namespace {
+ int g1 = 1;
+
+ // Note: This causes a warning about the function being undefined, but we
+ // currently have a problem with duplicate definitions when we call functions.
+ // This should be updated when that problem is fixed.
+ void f1(void);
+}
+
+
+// Test named namespace.
+namespace test {
+ int g2 = 2;
+ void f2(void);
+
+ // Test nested namespace.
+ namespace test2 {
+ int g3 = 3;
+ void f3(void);
+ }
+}
+
+// CHECK-DAG: cir.global internal @_ZN12_GLOBAL__N_12g1E = #cir.int<1> : !s32i
+// CHECK-DAG: cir.global external @_ZN4test2g2E = #cir.int<2> : !s32i
+// CHECK-DAG: cir.global external @_ZN4test5test22g3E = #cir.int<3> : !s32i
+// CHECK-DAG: cir.func @_ZN12_GLOBAL__N_12f1Ev()
+// CHECK-DAG: cir.func @_ZN4test2f2Ev()
+// CHECK-DAG: cir.func @_ZN4test5test22f3Ev()
+
+using namespace test;
+
+// Test global function.
+int f4(void) {
+ f1();
+ f2();
+ test2::f3();
+ return g1 + g2 + test2::g3;
+}
+
+// The namespace gets added during name mangling, so this is wrong but expected.
+// CHECK: cir.func @_Z2f4v()
+// CHECK: cir.call @_ZN12_GLOBAL__N_12f1Ev()
+// CHECK: cir.call @_ZN4test2f2Ev()
+// CHECK: cir.call @_ZN4test5test22f3Ev()
+// CHECK: %[[G1_ADDR:.*]] = cir.get_global @_ZN12_GLOBAL__N_12g1E : !cir.ptr<!s32i>
+// CHECK: %[[G1_VAL:.*]] = cir.load %[[G1_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: %[[G2_ADDR:.*]] = cir.get_global @_ZN4test2g2E : !cir.ptr<!s32i>
+// CHECK: %[[G2_VAL:.*]] = cir.load %[[G2_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: %[[SUM:.*]] = cir.binop(add, %[[G1_VAL]], %[[G2_VAL]]) nsw : !s32i
+// CHECK: %[[G3_ADDR:.*]] = cir.get_global @_ZN4test5test22g3E : !cir.ptr<!s32i>
+// CHECK: %[[G3_VAL:.*]] = cir.load %[[G3_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: %[[SUM2:.*]] = cir.binop(add, %[[SUM]], %[[G3_VAL]]) nsw : !s32i
More information about the cfe-commits
mailing list