From 82b7d7bc723051d8db4e21883e9072fe3ad99305 Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 18 Oct 2010 21:28:44 +0000 Subject: [PATCH] Fix some bugs in local class mangling brought up in PR8355. 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 | 40 ++++----- test/CodeGenCXX/mangle-abi-examples.cpp | 27 +++++++ .../CodeGenCXX/mangle-local-class-vtables.cpp | 61 ++++++++++++++ .../mangle-local-classes-nested.cpp | 81 +++++++++++++++++++ 4 files changed, 190 insertions(+), 19 deletions(-) create mode 100644 test/CodeGenCXX/mangle-abi-examples.cpp create mode 100644 test/CodeGenCXX/mangle-local-class-vtables.cpp create mode 100644 test/CodeGenCXX/mangle-local-classes-nested.cpp diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 36c908b099..e47d9cb43a 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -99,14 +99,14 @@ void MiscNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { namespace { -static const DeclContext *GetLocalClassFunctionDeclContext( - const DeclContext *DC) { - if (isa(DC)) { - while (!DC->isNamespace() && !DC->isTranslationUnit() && - !isa(DC)) - DC = DC->getParent(); - if (isa(DC)) - return DC; +static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { + const DeclContext *DC = dyn_cast(ND); + if (!DC) + DC = ND->getDeclContext(); + while (!DC->isNamespace() && !DC->isTranslationUnit()) { + if (isa(DC->getParent())) + return dyn_cast(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(DC) && ND->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = DC->getParent(); + else if (GetLocalClassDecl(ND)) { + mangleLocalName(ND); + return; + } while (isa(DC)) DC = DC->getParent(); @@ -853,15 +852,18 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { if (const ObjCMethodDecl *MD = dyn_cast(DC)) { mangleObjCMethodName(MD); - } - else if (const DeclContext *CDC = GetLocalClassFunctionDeclContext(DC)) { - mangleFunctionEncoding(cast(CDC)); + } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) { + mangleFunctionEncoding(cast(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 index 0000000000..7124078320 --- /dev/null +++ b/test/CodeGenCXX/mangle-abi-examples.cpp @@ -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 index 0000000000..d9d3afe459 --- /dev/null +++ b/test/CodeGenCXX/mangle-local-class-vtables.cpp @@ -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 index 0000000000..fafa5d4e58 --- /dev/null +++ b/test/CodeGenCXX/mangle-local-classes-nested.cpp @@ -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(); +} -- 2.40.0