Skip to content

[CIR] Upstream namepsace handling #137253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down Expand Up @@ -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;
}
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
55 changes: 55 additions & 0 deletions clang/test/CIR/CodeGen/namespace.cpp
Original file line number Diff line number Diff line change
@@ -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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is a function that cannot be defined, since the unnamed namespace results in no linkage, so you have a name that can be called now, but isn't defined. Do you mean that once we fix the call-functions bug, that we can actually jsut toss a definition in here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

}


// 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
Loading