aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-05-21 23:15:46 +0000
committerDouglas Gregor <dgregor@apple.com>2011-05-21 23:15:46 +0000
commit84ee2eeec9f63e4938bafd060105fa4f0c9cd89b (patch)
treec1152607c7ab0a8c886f9380f3ed0b49b827876d
parent9625e44c0252485277a340746ed8ac950686156f (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.html3
-rw-r--r--lib/Lex/PPMacroExpansion.cpp2
-rw-r--r--lib/Sema/SemaOverload.cpp23
-rw-r--r--lib/Sema/SemaTemplate.cpp22
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp2
-rw-r--r--test/SemaCXX/nullptr.cpp57
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;
+}