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<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__detail")) {
+ DeclContext *DCParent = DC->getParent();
+ if (DCParent->isNamespace() &&
+ cast<NamespaceDecl>(DCParent)->getIdentifier() &&
+ cast<NamespaceDecl>(DCParent)->getIdentifier()->isStr("tr1")) {
+ DeclContext *DCParent2 = DCParent->getParent();
+ if (DCParent2->isNamespace() &&
+ cast<NamespaceDecl>(DCParent2)->getIdentifier() &&
+ cast<NamespaceDecl>(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;
}
// 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<typename T>
struct __is_pod {
};
--- /dev/null
+// 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<typename _Key, typename _Value, typename _Ex, bool __unique,
+ typename _Hashtable>
+ struct _Map_base { };
+
+} } }
+
+namespace std { namespace tr1 {
+ template<typename T>
+ struct X1 {
+ template<typename _Key2, typename _Pair, typename _Hashtable>
+ friend struct __detail::_Map_base;
+ };
+
+} }
+
+std::tr1::X1<int> x1i;