diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-10-23 00:32:41 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-10-23 00:32:41 +0000 |
commit | 2ddcbab8ff9cf1c41ddb287145b101aa97a027ae (patch) | |
tree | 1adc8c93d29d7157edd79ea7b39988cb453fe089 | |
parent | d7fa5e420d933dc2b354ff307e1344e380e45d01 (diff) | |
download | bcm5719-llvm-2ddcbab8ff9cf1c41ddb287145b101aa97a027ae.tar.gz bcm5719-llvm-2ddcbab8ff9cf1c41ddb287145b101aa97a027ae.zip |
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!
llvm-svn: 166455
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 16 | ||||
-rw-r--r-- | clang/test/SemaCXX/libstdcxx_common_type_hack.cpp | 33 | ||||
-rw-r--r-- | clang/www/cxx_status.html | 7 |
3 files changed, 53 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ee9d529c69e..19c46ab9c97 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -158,6 +158,22 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, 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) diff --git a/clang/test/SemaCXX/libstdcxx_common_type_hack.cpp b/clang/test/SemaCXX/libstdcxx_common_type_hack.cpp new file mode 100644 index 00000000000..e9cb22f9dab --- /dev/null +++ b/clang/test/SemaCXX/libstdcxx_common_type_hack.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify + +// This is a test for an egregious hack in Clang that works around +// an issue with GCC's <type_traits> implementation. std::common_type +// relies on pre-standard rules for decltype(), in which it doesn't +// produce reference types so frequently. + +#ifdef BE_THE_HEADER + +#pragma GCC system_header +namespace std { + template<typename T> T &&declval(); + + template<typename...Ts> struct common_type {}; + template<typename A, typename B> struct common_type<A, B> { + // Under the rules in the standard, this always produces a + // reference type. + typedef decltype(true ? declval<A>() : declval<B>()) type; + }; +} + +#else + +#define BE_THE_HEADER +#include "libstdcxx_common_type_hack.cpp" + +using T = int; +using T = std::common_type<int, int>::type; + +using U = int; // expected-note {{here}} +using U = decltype(true ? std::declval<int>() : std::declval<int>()); // expected-error {{different types}} + +#endif diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index dbf5797c050..b4821a1fd85 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -40,10 +40,11 @@ <p>You can use Clang in C++11 mode either with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++. -Patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>, +Patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a> +work with Clang in C++11 mode. Patches are also needed to make <a href="libstdc++4.6-clang11.patch">libstdc++-4.6</a>, -and <a href="libstdc++4.7-clang11.patch">libstdc++-4.7</a> work with Clang in -C++11 mode.</p> +and <a href="libstdc++4.7-clang11.patch">libstdc++-4.7</a> work with Clang +releases prior to version 3.2 in C++11 mode.</p> <table width="689" border="1" cellspacing="0"> <tr> |