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
This commit is contained in:
Douglas Gregor 2011-05-21 23:15:46 +00:00
Родитель 9625e44c02
Коммит 84ee2eeec9
6 изменённых файлов: 98 добавлений и 11 удалений

Просмотреть файл

@ -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>

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);
}
}
}
}

Просмотреть файл

@ -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.

Просмотреть файл

@ -17,7 +17,7 @@ int has_nullptr();
int no_nullptr();
#endif
// CHECK-0X: no_nullptr
// CHECK-0X: has_nullptr
// CHECK-NO-0X: no_nullptr

Просмотреть файл

@ -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;
}