PR21565 Add an egregious hack to support broken libstdc++ headers that declare
a member named 'swap' and then expect unqualified lookup for the name 'swap' in
its exception specification to find anything else.

Without delay-parsed exception specifications, this was ill-formed (NDR) by
[basic.scope.class]p1, rule 2. With delay-parsed exception specifications, the
call to 'swap' unambiguously finds the function being declared, which then
fails because the arguments don't work for that function.

llvm-svn: 221955
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index c35de6b..7175c01 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -35,6 +35,33 @@
   return T->getAs<FunctionProtoType>();
 }
 
+/// HACK: libstdc++ has a bug where it shadows std::swap with a member
+/// swap function then tries to call std::swap unqualified from the exception
+/// specification of that function. This function detects whether we're in
+/// such a case and turns off delay-parsing of exception specifications.
+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 || RD->getEnclosingNamespaceContext() != getStdNamespace() ||
+      !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
+      !D.getIdentifier() || !D.getIdentifier()->isStr("swap"))
+    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)
+      .Default(false);
+}
+
 /// CheckSpecifiedExceptionType - Check if the given type is valid in an
 /// exception specification. Incomplete types, or pointers to incomplete types
 /// other than void are not allowed.