diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-05-21 23:15:46 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-05-21 23:15:46 +0000 |
commit | 84ee2eeec9f63e4938bafd060105fa4f0c9cd89b (patch) | |
tree | c1152607c7ab0a8c886f9380f3ed0b49b827876d | |
parent | 9625e44c0252485277a340746ed8ac950686156f (diff) |
Audit and finish the implementation of C++0x nullptr, fixing two
minor issues along the way:
- Non-type template parameters of type 'std::nullptr_t' were not
permitted.
- We didn't properly introduce built-in operators for nullptr ==,
!=, <, <=, >=, or > as candidate functions .
To my knowledge, there's only one (minor but annoying) part of nullptr
that hasn't been implemented: catching a thrown 'nullptr' as a pointer
or pointer-to-member, per C++0x [except.handle]p4.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131813 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/LanguageExtensions.html | 3 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 22 | ||||
-rw-r--r-- | test/Lexer/has_feature_cxx0x.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/nullptr.cpp | 57 |
6 files changed, 98 insertions, 11 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 066677c3d7..bc8ecb1bc9 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -449,8 +449,7 @@ is enabled. clang does not currently implement this feature.</p> <p>Use <tt>__has_feature(cxx_nullptr)</tt> or <tt>__has_extension(cxx_nullptr)</tt> to determine if support for -<tt>nullptr</tt> is enabled. clang does not yet fully implement this -feature.</p> +<tt>nullptr</tt> is enabled.</p> <h4 id="cxx_override_control">C++0x <tt>override control</tt></h3> diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 6a9d4abef1..01cd75fa84 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -571,7 +571,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) .Case("cxx_noexcept", LangOpts.CPlusPlus0x) - //.Case("cxx_nullptr", false) + .Case("cxx_nullptr", LangOpts.CPlusPlus0x) .Case("cxx_override_control", LangOpts.CPlusPlus0x) .Case("cxx_range_for", LangOpts.CPlusPlus0x) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index e8dd56f66f..c3f330e371 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4705,6 +4705,10 @@ class BuiltinCandidateTypeSet { /// were present in the candidate set. bool HasArithmeticOrEnumeralTypes; + /// \brief A flag indicating whether the nullptr type was present in the + /// candidate set. + bool HasNullPtrType; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -4723,6 +4727,7 @@ public: BuiltinCandidateTypeSet(Sema &SemaRef) : HasNonRecordTypes(false), HasArithmeticOrEnumeralTypes(false), + HasNullPtrType(false), SemaRef(SemaRef), Context(SemaRef.Context) { } @@ -4755,6 +4760,7 @@ public: bool hasNonRecordTypes() { return HasNonRecordTypes; } bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; } + bool hasNullPtrType() const { return HasNullPtrType; } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -4915,6 +4921,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // extension. HasArithmeticOrEnumeralTypes = true; VectorTypes.insert(Ty); + } else if (Ty->isNullPtrType()) { + HasNullPtrType = true; } else if (AllowUserConversions && TyRec) { // No conversion functions in incomplete types. if (SemaRef.RequireCompleteType(Loc, Ty, 0)) @@ -5374,8 +5382,8 @@ public: // C++ [over.built]p15: // - // For every pointer or enumeration type T, there exist - // candidate operator functions of the form + // For every T, where T is an enumeration type, a pointer type, or + // std::nullptr_t, there exist candidate operator functions of the form // // bool operator<(T, T); // bool operator>(T, T); @@ -5460,6 +5468,17 @@ public: S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet); } + + if (CandidateTypes[ArgIdx].hasNullPtrType()) { + CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); + if (AddedTypes.insert(NullPtrTy) && + !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, + NullPtrTy))) { + QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); + } + } } } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f3392e4183..8e7e1a12dd 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -602,8 +602,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { T->isPointerType() || // -- reference to object or reference to function, T->isReferenceType() || - // -- pointer to member. + // -- pointer to member, T->isMemberPointerType() || + // -- std::nullptr_t. + T->isNullPtrType() || // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. T->isDependentType()) @@ -3756,10 +3758,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // from a template argument of type std::nullptr_t to a non-type // template parameter of type pointer to object, pointer to // function, or pointer-to-member, respectively. - if (ArgType->isNullPtrType() && - (ParamType->isPointerType() || ParamType->isMemberPointerType())) { - Converted = TemplateArgument((NamedDecl *)0); - return Owned(Arg); + if (ArgType->isNullPtrType()) { + if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { + Converted = TemplateArgument((NamedDecl *)0); + return Owned(Arg); + } + + if (ParamType->isNullPtrType()) { + llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true); + Converted = TemplateArgument(Zero, Context.NullPtrTy); + return Owned(Arg); + } } // Handle pointer-to-function, reference-to-function, and @@ -4053,6 +4062,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, Arg.getAsIntegral()->getBoolValue(), T, Loc)); + if (T->isNullPtrType()) + return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc)); + // If this is an enum type that we're instantiating, we need to use an integer // type the same size as the enumerator. We don't want to build an // IntegerLiteral with enum type. diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp index 57354f866e..ca5f868d9b 100644 --- a/test/Lexer/has_feature_cxx0x.cpp +++ b/test/Lexer/has_feature_cxx0x.cpp @@ -17,7 +17,7 @@ int has_nullptr(); int no_nullptr(); #endif -// CHECK-0X: no_nullptr +// CHECK-0X: has_nullptr // CHECK-NO-0X: no_nullptr diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp index 84c80aa286..d69af588a7 100644 --- a/test/SemaCXX/nullptr.cpp +++ b/test/SemaCXX/nullptr.cpp @@ -60,6 +60,10 @@ nullptr_t f(nullptr_t null) // You can reinterpret_cast nullptr to an integer. (void)reinterpret_cast<uintptr_t>(nullptr); + (void)reinterpret_cast<uintptr_t>(*pn); + + int *ip = *pn; + if (*pn) { } // You can throw nullptr. throw nullptr; @@ -104,3 +108,56 @@ namespace test3 { f("%p", nullptr); } } + +int array0[__is_scalar(nullptr_t)? 1 : -1]; +int array1[__is_pod(nullptr_t)? 1 : -1]; +int array2[sizeof(nullptr_t) == sizeof(void*)? 1 : -1]; + +// FIXME: when we implement constexpr, this will be testable. +#if 0 +int relational0[nullptr < nullptr? -1 : 1]; +int relational1[nullptr > nullptr? -1 : 1]; +int relational2[nullptr <= nullptr? 1 : -1]; +int relational3[nullptr >= nullptr? 1 : -1]; +int equality[nullptr == nullptr? 1 : -1]; +int inequality[nullptr != nullptr? -1 : 1]; +#endif + +namespace overloading { + int &f1(int*); + float &f1(bool); + + void test_f1() { + int &ir = (f1)(nullptr); + } + + struct ConvertsToNullPtr { + operator nullptr_t() const; + }; + + void test_conversion(ConvertsToNullPtr ctn) { + (void)(ctn == ctn); + (void)(ctn != ctn); + (void)(ctn <= ctn); + (void)(ctn >= ctn); + (void)(ctn < ctn); + (void)(ctn > ctn); + } +} + +namespace templates { + template<typename T, nullptr_t Value> + struct X { + X() { ptr = Value; } + + T *ptr; + }; + + X<int, nullptr> x; + + + template<int (*fp)(int), int* p, int A::* pmd, int (A::*pmf)(int)> + struct X2 {}; + + X2<nullptr, nullptr, nullptr, nullptr> x2; +} |