Extend hack to work around bad exception specifications for 'swap' members to

also cover libstdc++'s std::__debug::array and std::__profile::array.

llvm-svn: 284669
This commit is contained in:
Richard Smith 2016-10-19 23:47:37 +00:00
parent 210030ba95
commit 628954652f
2 changed files with 37 additions and 10 deletions

View File

@ -43,23 +43,36 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
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);
}

View File

@ -13,6 +13,9 @@
// 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.
@ -32,6 +35,13 @@ namespace std {
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)));
@ -47,6 +57,10 @@ namespace std {
// void swap(vector &other) noexcept(noexcept(do_swap(member, other.member)));
// A member;
// };
#ifdef NAMESPACE
}
#endif
}
#else
@ -55,8 +69,8 @@ namespace std {
#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;