-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[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
Conversation
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).
@llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces). Full diff: https://github.com/llvm/llvm-project/pull/137253.diff 4 Files Affected:
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
|
@llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces). Full diff: https://github.com/llvm/llvm-project/pull/137253.diff 4 Files Affected:
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
|
// 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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).
This adds the handlers for Decl::Namespace and Decl::UsingDirective (which is needed for anonymous namespaces).