Ugly ugly hack for libstdc++-4.6 and libstdc++-4.7 compatibility. These
libraries have an incorrect definition of std::common_type (inherited from a
bug in the standard -- see LWG issue 2141), whereby they produce reference
types when they should not.

If we instantiate a typedef named std::common_type<...>::type, which is defined
in a system header as decltype(... ? ... : ...), and the decltype produces a
reference type, convert it to the non-reference type. (This doesn't affect any
LWG2141-conforming implementation of common_type, such as libc++'s, because the
default implementation of common_type<...>::type isn't supposed to produce a
reference type.)

This is horrible. I'm really sorry. :( Better ideas appreciated!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166455 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ee9d529..19c46ab 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -158,6 +158,22 @@
     SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
   }
 
+  // HACK: g++ has a bug where it gets the value kind of ?: wrong.
+  // libstdc++ relies upon this bug in its implementation of common_type.
+  // If we happen to be processing that implementation, fake up the g++ ?:
+  // semantics. See LWG issue 2141 for more information on the bug.
+  const DecltypeType *DT = DI->getType()->getAs<DecltypeType>();
+  CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext());
+  if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) &&
+      DT->isReferenceType() &&
+      RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() &&
+      RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") &&
+      D->getIdentifier() && D->getIdentifier()->isStr("type") &&
+      SemaRef.getSourceManager().isInSystemHeader(D->getLocStart()))
+    // Fold it to the (non-reference) type which g++ would have produced.
+    DI = SemaRef.Context.getTrivialTypeSourceInfo(
+      DI->getType().getNonReferenceType());
+
   // Create the new typedef
   TypedefNameDecl *Typedef;
   if (IsTypeAlias)