зеркало из https://github.com/microsoft/clang.git
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:
Родитель
9625e44c02
Коммит
84ee2eeec9
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче