From c53d0d762010217d02da5aa14be171817d63e3fe Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 8 Apr 2010 18:16:15 +0000 Subject: [PATCH] Introduce an egregious hack to work around a bug in libstdc++ 4.2.x's header, where a friend class template std::tr1::__detail::_Map_base is declared with the wrong template parameters. GCC doesn't catch the problem, so Clang does a little back-flip to avoid diagnosing just this one instance of the problem. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100790 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateInstantiateDecl.cpp | 41 +++++++++++++++++++++--- test/SemaCXX/libstdcxx_is_pod_hack.cpp | 6 ++++ test/SemaCXX/libstdcxx_map_base_hack.cpp | 25 +++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 test/SemaCXX/libstdcxx_map_base_hack.cpp diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9df345a11f..e4690466d3 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -688,19 +688,52 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return 0; } + bool AdoptedPreviousTemplateParams = false; if (PrevClassTemplate) { + bool Complain = true; + + // HACK: libstdc++ 4.2.1 contains an ill-formed friend class + // template for struct std::tr1::__detail::_Map_base, where the + // template parameters of the friend declaration don't match the + // template parameters of the original declaration. In this one + // case, we don't complain about the ill-formed friend + // declaration. + if (isFriend && Pattern->getIdentifier() && + Pattern->getIdentifier()->isStr("_Map_base") && + DC->isNamespace() && + cast(DC)->getIdentifier() && + cast(DC)->getIdentifier()->isStr("__detail")) { + DeclContext *DCParent = DC->getParent(); + if (DCParent->isNamespace() && + cast(DCParent)->getIdentifier() && + cast(DCParent)->getIdentifier()->isStr("tr1")) { + DeclContext *DCParent2 = DCParent->getParent(); + if (DCParent2->isNamespace() && + cast(DCParent2)->getIdentifier() && + cast(DCParent2)->getIdentifier()->isStr("std") && + DCParent2->getParent()->isTranslationUnit()) + Complain = false; + } + } + TemplateParameterList *PrevParams = PrevClassTemplate->getTemplateParameters(); // Make sure the parameter lists match. if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, - /*Complain=*/true, - Sema::TPL_TemplateMatch)) - return 0; + Complain, + Sema::TPL_TemplateMatch)) { + if (Complain) + return 0; + + AdoptedPreviousTemplateParams = true; + InstParams = PrevParams; + } // Do some additional validation, then merge default arguments // from the existing declarations. - if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + if (!AdoptedPreviousTemplateParams && + SemaRef.CheckTemplateParameterList(InstParams, PrevParams, Sema::TPC_ClassTemplate)) return 0; } diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp index 7a4bebca86..2e92032195 100644 --- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp +++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp @@ -1,5 +1,11 @@ // RUN: %clang_cc1 -fsyntax-only %s +// This is a test for an egregious hack in Clang that works around +// issues with GCC's evolution. libstdc++ 4.2.x uses __is_pod as an +// identifier (to declare a struct template like the one below), while +// GCC 4.3 and newer make __is_pod a keyword. Clang treats __is_pod as +// a keyword *unless* it is introduced following the struct keyword. + template struct __is_pod { }; diff --git a/test/SemaCXX/libstdcxx_map_base_hack.cpp b/test/SemaCXX/libstdcxx_map_base_hack.cpp new file mode 100644 index 0000000000..a556281fc0 --- /dev/null +++ b/test/SemaCXX/libstdcxx_map_base_hack.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only %s + +// libstdc++ 4.2.x contains a bug where a friend struct template +// declaration for std::tr1::__detail::_Map base has different +// template arguments than the real declaration. Clang has an +// egregious hack to work around this problem, since we can't modify +// all of the world's libstdc++'s. + +namespace std { namespace tr1 { namespace __detail { + template + struct _Map_base { }; + +} } } + +namespace std { namespace tr1 { + template + struct X1 { + template + friend struct __detail::_Map_base; + }; + +} } + +std::tr1::X1 x1i; -- 2.40.0