Correctly mangle the 'std' namespace inside extern "C++" blocks.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90544 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 1aea187..a20dec6 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -247,14 +247,32 @@
   mangleBareFunctionType(FT, MangleReturnType);
 }
 
-static bool isStdNamespace(const NamespaceDecl *NS) {
+/// isStd - Return whether a given namespace is the 'std' namespace.
+static bool isStd(const NamespaceDecl *NS) {
   const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
   return II && II->isStr("std");
 }
 
+static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
+  while (isa<LinkageSpecDecl>(DC)) {
+    assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
+           LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
+    DC = DC->getParent();
+  }
+  
+  return DC;
+}
+
+// isStdNamespace - Return whether a given decl context is a toplevel 'std'
+// namespace.
 static bool isStdNamespace(const DeclContext *DC) {
-  return DC->isNamespace() && DC->getParent()->isTranslationUnit() &&
-    isStdNamespace(cast<NamespaceDecl>(DC));
+  if (!DC->isNamespace())
+    return false;
+  
+  if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit())
+    return false;
+  
+  return isStd(cast<NamespaceDecl>(DC));
 }
 
 static const TemplateDecl *
@@ -317,12 +335,7 @@
 void CXXNameMangler::mangleName(const TemplateDecl *TD,
                                 const TemplateArgument *TemplateArgs,
                                 unsigned NumTemplateArgs) {
-  const DeclContext *DC = TD->getDeclContext();
-  while (isa<LinkageSpecDecl>(DC)) {
-    assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
-           LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
-    DC = DC->getParent();
-  }
+  const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext());
 
   if (DC->isTranslationUnit() || isStdNamespace(DC)) {
     mangleUnscopedTemplateName(TD);
@@ -1244,11 +1257,8 @@
 
 bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
   // <substitution> ::= St # ::std::
-  // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of
-  // __ZNKSt9type_infoeqERKS_
-  // FIXME: __ZSt13set_terminatePFvvE comes out as __ZNSt13set_terminateEPFvvE.
   if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
-    if (isStdNamespace(NS)) {
+    if (isStd(NS)) {
       Out << "St";
       return true;
     }
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index fbce204..8a410b8 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -37,3 +37,13 @@
 
 // CHECK: _Z1fSo
 void f(std::basic_ostream<char, std::char_traits<char> >) { }
+
+extern "C++" {
+namespace std
+{
+  typedef void (*terminate_handler) ();
+  
+  // CHECK: _ZSt13set_terminatePFvvE
+  terminate_handler set_terminate(terminate_handler) { return 0; }
+}
+}