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 <akay...@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits