]> granicus.if.org Git - clang/commitdiff
Fix some bugs in local class mangling brought up in PR8355.
authorJohn McCall <rjmccall@apple.com>
Mon, 18 Oct 2010 21:28:44 +0000 (21:28 +0000)
committerJohn McCall <rjmccall@apple.com>
Mon, 18 Oct 2010 21:28:44 +0000 (21:28 +0000)
Patch by Richard Smith!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116752 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/Mangle.cpp
test/CodeGenCXX/mangle-abi-examples.cpp [new file with mode: 0644]
test/CodeGenCXX/mangle-local-class-vtables.cpp [new file with mode: 0644]
test/CodeGenCXX/mangle-local-classes-nested.cpp [new file with mode: 0644]

index 36c908b099aea0724f90f310263019df3881e006..e47d9cb43a6222794d65cb68a4c5d14bbe55620a 100644 (file)
@@ -99,14 +99,14 @@ void MiscNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
 
 namespace {
 
-static const DeclContext *GetLocalClassFunctionDeclContext(
-                                                      const DeclContext *DC) {
-  if (isa<CXXRecordDecl>(DC)) {
-    while (!DC->isNamespace() && !DC->isTranslationUnit() &&
-           !isa<FunctionDecl>(DC))
-      DC = DC->getParent();
-    if (isa<FunctionDecl>(DC))
-      return DC;
+static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
+  const DeclContext *DC = dyn_cast<DeclContext>(ND);
+  if (!DC)
+    DC = ND->getDeclContext();
+  while (!DC->isNamespace() && !DC->isTranslationUnit()) {
+    if (isa<FunctionDecl>(DC->getParent()))
+      return dyn_cast<CXXRecordDecl>(DC);
+    DC = DC->getParent();
   }
   return 0;
 }
@@ -433,16 +433,15 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
   //
   const DeclContext *DC = ND->getDeclContext();
 
-  if (GetLocalClassFunctionDeclContext(DC)) {
-    mangleLocalName(ND);
-    return;
-  }
-
   // If this is an extern variable declared locally, the relevant DeclContext
   // is that of the containing namespace, or the translation unit.
   if (isa<FunctionDecl>(DC) && ND->hasLinkage())
     while (!DC->isNamespace() && !DC->isTranslationUnit())
       DC = DC->getParent();
+  else if (GetLocalClassDecl(ND)) {
+    mangleLocalName(ND);
+    return;
+  }
 
   while (isa<LinkageSpecDecl>(DC))
     DC = DC->getParent();
@@ -853,15 +852,18 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
 
   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
    mangleObjCMethodName(MD);
-  }
-  else if (const DeclContext *CDC = GetLocalClassFunctionDeclContext(DC)) {
-    mangleFunctionEncoding(cast<FunctionDecl>(CDC));
+  } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
+    mangleFunctionEncoding(cast<FunctionDecl>(RD->getDeclContext()));
     Out << 'E';
-    mangleNestedName(ND, DC, true /*NoFunction*/);
 
-    // FIXME. This still does not cover all cases.
+    // Mangle the name relative to the closest enclosing function.
+    if (ND == RD) // equality ok because RD derived from ND above
+      mangleUnqualifiedName(ND);
+    else
+      mangleNestedName(ND, DC, true /*NoFunction*/);
+
     unsigned disc;
-    if (Context.getNextDiscriminator(ND, disc)) {
+    if (Context.getNextDiscriminator(RD, disc)) {
       if (disc < 10)
         Out << '_' << disc;
       else
diff --git a/test/CodeGenCXX/mangle-abi-examples.cpp b/test/CodeGenCXX/mangle-abi-examples.cpp
new file mode 100644 (file)
index 0000000..7124078
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @_ZTVZ3foovEN1C1DE =
+// CHECK: @_ZTVZN1A3fooEiE1B =
+// CHECK: define {{.*}} @_ZZZ3foovEN1C3barEvEN1E3bazEv(
+
+// Itanium C++ ABI examples.
+struct A {
+  void foo (int) {
+    struct B { virtual ~B() {} };
+    B();
+  }
+};
+void foo () {
+  struct C {
+    struct D { virtual ~D() {} };
+    void bar () {
+      struct E {
+        void baz() { }
+      };
+      E().baz();
+    }
+  };
+  A().foo(0);
+  C::D();
+  C().bar();
+}
diff --git a/test/CodeGenCXX/mangle-local-class-vtables.cpp b/test/CodeGenCXX/mangle-local-class-vtables.cpp
new file mode 100644 (file)
index 0000000..d9d3afe
--- /dev/null
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @_ZTVZN1J1KEvE1C = {{.*}} @_ZTIZN1J1KEvE1C {{.*}} @_ZZN1J1KEvENK1C1FEv 
+// CHECK: @_ZTIZN1J1KEvE1C = {{.*}} @_ZTSZN1J1KEvE1C
+// CHECK: @_ZTVZ1GvE1C_1 = {{.*}} @_ZTIZ1GvE1C_1 {{.*}} @_ZZ1GvENK1C1FE_1v 
+// CHECK: @_ZTIZ1GvE1C_1 = {{.*}} @_ZTSZ1GvE1C_1
+// CHECK: @_ZTVZ1GvE1C_0 = {{.*}} @_ZTIZ1GvE1C_0 {{.*}} @_ZZ1GvENK1C1FE_0v 
+// CHECK: @_ZTIZ1GvE1C_0 = {{.*}} @_ZTSZ1GvE1C_0
+// CHECK: @_ZTVZ1GvE1C = {{.*}} @_ZTIZ1GvE1C {{.*}} @_ZZ1GvENK1C1FEv 
+// CHECK: @_ZTIZ1GvE1C = {{.*}} @_ZTSZ1GvE1C
+
+// CHECK: define {{.*}} @_ZZN1J1KEvEN1CC2Ev(
+// CHECK: define {{.*}} @_ZZN1J1KEvENK1C1FEv(
+// CHECK: define {{.*}} @_ZZ1GvEN1CC2E_1v(
+// CHECK: define {{.*}} @_ZZ1GvENK1C1FE_1v(
+// CHECK: define {{.*}} @_ZZ1GvENK1C1HE_1v(
+// CHECK: define {{.*}} @_ZZ1GvEN1CC2E_0v(
+// CHECK: define {{.*}} @_ZZ1GvENK1C1FE_0v(
+// CHECK: define {{.*}} @_ZZ1GvENK1C1GE_0v(
+// CHECK: define {{.*}} @_ZZ1GvEN1CC2Ev(
+// CHECK: define {{.*}} @_ZZ1GvENK1C1FEv(
+
+struct I { 
+  virtual void F() const = 0;
+};
+
+void Go(const I &i);
+
+void G() { 
+  { 
+    struct C : I { 
+      void F() const {}
+    };
+    Go(C());
+  }
+  { 
+    struct C : I { 
+      void F() const { G(); }
+      void G() const {}
+    };
+    Go(C());
+  }
+  { 
+    struct C : I { 
+      void F() const { H(); }
+      void H() const {}
+    };
+    Go(C());
+  }
+}
+
+struct J {
+  void K();
+};
+
+void J::K() {
+  struct C : I {
+    void F() const {}
+  };
+  Go(C());
+}
diff --git a/test/CodeGenCXX/mangle-local-classes-nested.cpp b/test/CodeGenCXX/mangle-local-classes-nested.cpp
new file mode 100644 (file)
index 0000000..fafa5d4
--- /dev/null
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: @_ZTVZZ1HvEN1S1IEvE1S = 
+
+// CHECK: define {{.*}} @_Z2L1v(
+// CHECK: define {{.*}} @_ZZ2L1vEN1S2L2Ev(
+// CHECK: define {{.*}} @_ZZ2L1vEN1S2L2E_0v(
+// CHECK: define {{.*}} @_ZZ1FvEN1S1T1S1T1GEv(
+// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2E_0vEN1S3L3cEv(
+// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2E_0vEN1S3L3dE_0v(
+// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2EvEN1S3L3aEv(
+// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2EvEN1S3L3bE_0v(
+
+void L1() {
+  {
+    struct S {
+      void L2() {
+        {
+          struct S {
+            void L3a() {}
+          };
+          S().L3a();
+        }
+        {
+          struct S {
+            void L3b() {}
+          };
+          S().L3b();
+        }
+      }
+    };
+    S().L2();
+  }
+  {
+    struct S {
+      void L2() {
+        {
+          struct S {
+            void L3c() {}
+          };
+          S().L3c();
+        }
+        {
+          struct S {
+            void L3d() {}
+          };
+          S().L3d();
+        }
+      }
+    };
+    S().L2();
+  }
+}
+
+void F() {
+  struct S {
+    struct T {
+      struct S {
+        struct T {
+          void G() {}
+        };
+      };
+    };
+  };
+  S::T::S::T().G();
+}
+
+struct B { virtual void Foo() = 0; };
+void G(const B &);
+
+void H() {
+  struct S {
+    void I() {
+      struct S : B {
+        virtual void Foo() {}
+      };
+      G(S());
+    }
+  };
+  S().I();
+}