auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
// All the problem cases are member functions named "swap" within class
- // templates declared directly within namespace std.
- if (!RD || !getStdNamespace() ||
- !RD->getEnclosingNamespaceContext()->Equals(getStdNamespace()) ||
- !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
+ // templates declared directly within namespace std or std::__debug or
+ // std::__profile.
+ if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
!D.getIdentifier() || !D.getIdentifier()->isStr("swap"))
return false;
+ auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext());
+ if (!ND)
+ return false;
+
+ bool IsInStd = ND->isStdNamespace();
+ if (!IsInStd) {
+ // This isn't a direct member of namespace std, but it might still be
+ // libstdc++'s std::__debug::array or std::__profile::array.
+ IdentifierInfo *II = ND->getIdentifier();
+ if (!II || !(II->isStr("__debug") || II->isStr("__profile")) ||
+ !ND->isInStdNamespace())
+ return false;
+ }
+
// Only apply this hack within a system header.
if (!Context.getSourceManager().isInSystemHeader(D.getLocStart()))
return false;
return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())
.Case("array", true)
- .Case("pair", true)
- .Case("priority_queue", true)
- .Case("stack", true)
- .Case("queue", true)
+ .Case("pair", IsInStd)
+ .Case("priority_queue", IsInStd)
+ .Case("stack", IsInStd)
+ .Case("queue", IsInStd)
.Default(false);
}
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=priority_queue
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=stack
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=queue
+//
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DNAMESPACE=__debug
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DNAMESPACE=__profile
// MSVC's standard library uses a very similar pattern that relies on delayed
// parsing of exception specifications.
swap(a, b);
}
+#ifdef NAMESPACE
+ namespace NAMESPACE {
+#define STD_CLASS std::NAMESPACE::CLASS
+#else
+#define STD_CLASS std::CLASS
+#endif
+
template<typename A, typename B> struct CLASS {
#ifdef MSVC
void swap(CLASS &other) noexcept(noexcept(do_swap(member, other.member)));
// void swap(vector &other) noexcept(noexcept(do_swap(member, other.member)));
// A member;
// };
+
+#ifdef NAMESPACE
+ }
+#endif
}
#else
#include __FILE__
struct X {};
-using PX = std::CLASS<X, X>;
-using PI = std::CLASS<int, int>;
+using PX = STD_CLASS<X, X>;
+using PI = STD_CLASS<int, int>;
void swap(X &, X &) noexcept;
PX px;
PI pi;