diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 26 | ||||
| -rw-r--r-- | clang/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp | 34 |
2 files changed, 57 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 4e55da328a9..9d7fcda8fdd 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4135,6 +4135,24 @@ static void TryUserDefinedConversion(Sema &S, } } +/// An egregious hack for compatibility with libstdc++-4.2: in <tr1/hashtable>, +/// a function with a pointer return type contains a 'return false;' statement. +/// In C++11, 'false' is not a null pointer, so this breaks the build of any +/// code using that header. +/// +/// Work around this by treating 'return false;' as zero-initializing the result +/// if it's used in a pointer-returning function in a system header. +static bool isLibstdcxxPointerReturnFalseHack(Sema &S, + const InitializedEntity &Entity, + const Expr *Init) { + return S.getLangOpts().CPlusPlus11 && + Entity.getKind() == InitializedEntity::EK_Result && + Entity.getType()->isPointerType() && + isa<CXXBoolLiteralExpr>(Init) && + !cast<CXXBoolLiteralExpr>(Init)->getValue() && + S.getSourceManager().isInSystemHeader(Init->getExprLoc()); +} + /// The non-zero enum values here are indexes into diagnostic alternatives. enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar }; @@ -4571,9 +4589,11 @@ InitializationSequence::InitializationSequence(Sema &S, AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); } else if (ICS.isBad()) { DeclAccessPair dap; - if (Initializer->getType() == Context.OverloadTy && - !S.ResolveAddressOfOverloadedFunction(Initializer - , DestType, false, dap)) + if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) { + AddZeroInitializationStep(Entity.getType()); + } else if (Initializer->getType() == Context.OverloadTy && + !S.ResolveAddressOfOverloadedFunction(Initializer, DestType, + false, dap)) SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else SetFailed(InitializationSequence::FK_ConversionFailed); diff --git a/clang/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp b/clang/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp new file mode 100644 index 00000000000..ad936095eec --- /dev/null +++ b/clang/test/SemaCXX/libstdcxx_pointer_return_false_hack.cpp @@ -0,0 +1,34 @@ +// 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 { + namespace tr1 { + template<typename T> struct hashnode; + template<typename T> struct hashtable { + typedef hashnode<T> node; + node *find_node() { + // This is ill-formed in C++11, per core issue 903, but we accept + // it anyway in a system header. + return false; + } + }; + } +} + +#else + +#define BE_THE_HEADER +#include "libstdcxx_pointer_return_false_hack.cpp" + +auto *test1 = std::tr1::hashtable<int>().find_node(); + +void *test2() { return false; } // expected-error {{cannot initialize}} + +#endif |

