From: Sebastian Redl
Date: Sun, 10 May 2009 18:38:11 +0000 (+0000)
Subject: Implement C++0x nullptr.
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6e8ed16ffef02b82995a90bdcf10ffff7d63839a;p=clang
Implement C++0x nullptr.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71405 91177308-0d34-0410-b5e6-96231b3b80d8
---
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 3afccdb61d..1f24dee0f3 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -174,7 +174,7 @@ public:
QualType UnsignedLongLongTy, UnsignedInt128Ty;
QualType FloatTy, DoubleTy, LongDoubleTy;
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
- QualType VoidPtrTy;
+ QualType VoidPtrTy, NullPtrTy;
QualType OverloadTy;
QualType DependentTy;
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 483f0e31d6..c34ded26a5 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -222,6 +222,24 @@ public:
virtual child_iterator child_end();
};
+/// CXXNullPtrLiteralExpr - [C++0x 2.14.7] C++ Pointer Literal
+class CXXNullPtrLiteralExpr : public Expr {
+ SourceLocation Loc;
+public:
+ CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) :
+ Expr(CXXNullPtrLiteralExprClass, Ty), Loc(l) {}
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXNullPtrLiteralExprClass;
+ }
+ static bool classof(const CXXNullPtrLiteralExpr *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets
/// the type_info that corresponds to the supplied type, or the (possibly
/// dynamic) type of the supplied expression.
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index 71dd77b4e5..b1b0531277 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -107,6 +107,7 @@ STMT(CXXConstCastExpr , CXXNamedCastExpr)
STMT(CXXFunctionalCastExpr , ExplicitCastExpr)
STMT(CXXTypeidExpr , Expr)
STMT(CXXBoolLiteralExpr , Expr)
+STMT(CXXNullPtrLiteralExpr , Expr)
STMT(CXXThisExpr , Expr)
STMT(CXXThrowExpr , Expr)
STMT(CXXDefaultArgExpr , Expr)
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 1d440ac214..22e36a8215 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -394,6 +394,7 @@ public:
bool isObjCQualifiedInterfaceType() const; // NSString
bool isObjCQualifiedIdType() const; // id
bool isTemplateTypeParmType() const; // C++ template type parameter
+ bool isNullPtrType() const; // C++0x nullptr_t
/// isDependentType - Whether this type is a dependent type, meaning
/// that its definition somehow depends on a template parameter
@@ -404,7 +405,7 @@ public:
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
/// pointers, and Objective-C interface, qualified id, and qualified
- /// interface types.
+ /// interface types, as well as nullptr_t.
bool hasPointerRepresentation() const;
/// hasObjCPointerRepresentation - Whether this type can represent
@@ -559,6 +560,8 @@ public:
Float, Double, LongDouble,
+ NullPtr, // This is the type of C++0x 'nullptr'.
+
Overload, // This represents the type of an overloaded function declaration.
Dependent // This represents the type of a type-dependent expression.
};
@@ -1926,7 +1929,7 @@ inline bool Type::isOverloadableType() const {
inline bool Type::hasPointerRepresentation() const {
return (isPointerType() || isReferenceType() || isBlockPointerType() ||
isObjCInterfaceType() || isObjCQualifiedIdType() ||
- isObjCQualifiedInterfaceType());
+ isObjCQualifiedInterfaceType() || isNullPtrType());
}
inline bool Type::hasObjCPointerRepresentation() const {
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index bb5c91b8e0..29f408316b 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -319,7 +319,9 @@ namespace clang {
/// \brief The '__uint128_t' type.
PREDEF_TYPE_UINT128_ID = 21,
/// \brief The '__int128_t' type.
- PREDEF_TYPE_INT128_ID = 22
+ PREDEF_TYPE_INT128_ID = 22,
+ /// \brief The type of 'nullptr'.
+ PREDEF_TYPE_NULLPTR_ID = 23
};
/// \brief The number of predefined type IDs that are reserved for
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index fdd2b2abac..f70c9f0591 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -963,7 +963,12 @@ public:
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
- tok::TokenKind Kind) {
+ tok::TokenKind Kind) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
+ virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc) {
return ExprEmpty();
}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4aed59f37e..133e8c20b8 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -276,6 +276,9 @@ void ASTContext::InitBuiltinTypes() {
// void * type
VoidPtrTy = getPointerType(VoidTy);
+
+ // nullptr type (C++0x 2.14.7)
+ InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
}
//===----------------------------------------------------------------------===//
@@ -431,6 +434,9 @@ ASTContext::getTypeInfo(const Type *T) {
Width = Target.getLongDoubleWidth();
Align = Target.getLongDoubleAlign();
break;
+ case BuiltinType::NullPtr:
+ Width = Target.getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
+ Align = Target.getPointerAlign(0); // == sizeof(void*)
}
break;
case Type::FixedWidthInt:
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 77a25f6fc0..0d38dd2cd1 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1377,6 +1377,10 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const
return true;
}
+ // C++0x nullptr_t is always a null pointer constant.
+ if (getType()->isNullPtrType())
+ return true;
+
// This expression must be an integer type.
if (!getType()->isIntegerType())
return false;
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index b05bf7d4ac..8176db5bf5 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -44,6 +44,14 @@ Stmt::child_iterator CXXBoolLiteralExpr::child_end() {
return child_iterator();
}
+// CXXNullPtrLiteralExpr
+Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() {
+ return child_iterator();
+}
+
// CXXThisExpr
Stmt::child_iterator CXXThisExpr::child_begin() { return child_iterator(); }
Stmt::child_iterator CXXThisExpr::child_end() { return child_iterator(); }
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index aa4920f719..34b0187970 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -299,7 +299,9 @@ public:
{ return APValue((Expr*)0, 0); }
APValue VisitConditionalOperator(ConditionalOperator *E);
APValue VisitChooseExpr(ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
+ { return APValue((Expr*)0, 0); }
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 0f8284a2eb..cf1a255236 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -996,6 +996,10 @@ void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
OS << (Node->getValue() ? "true" : "false");
}
+void StmtPrinter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) {
+ OS << "nullptr";
+}
+
void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
OS << "this";
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index d6cf4bd0c3..b5a884085b 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -889,6 +889,12 @@ bool Type::isPromotableIntegerType() const {
return false;
}
+bool Type::isNullPtrType() const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ return BT->getKind() == BuiltinType::NullPtr;
+ return false;
+}
+
const char *BuiltinType::getName() const {
switch (getKind()) {
default: assert(0 && "Unknown builtin type!");
@@ -912,6 +918,7 @@ const char *BuiltinType::getName() const {
case Double: return "double";
case LongDouble: return "long double";
case WChar: return "wchar_t";
+ case NullPtr: return "nullptr_t";
case Overload: return "";
case Dependent: return "";
}
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index b61acbbe51..036389d4c0 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -499,6 +499,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// UNSUPPORTED: ::= Di # char32_t
// UNSUPPORTED: ::= Ds # char16_t
// ::= u # vendor extended type
+ // From our point of view, std::nullptr_t is a builtin, but as far as mangling
+ // is concerned, it's a type called std::nullptr_t.
switch (T->getKind()) {
case BuiltinType::Void: Out << 'v'; break;
case BuiltinType::Bool: Out << 'b'; break;
@@ -519,6 +521,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Float: Out << 'f'; break;
case BuiltinType::Double: Out << 'd'; break;
case BuiltinType::LongDouble: Out << 'e'; break;
+ case BuiltinType::NullPtr: Out << "St9nullptr_t"; break;
case BuiltinType::Overload:
case BuiltinType::Dependent:
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 9323620938..759865c7eb 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1676,6 +1676,7 @@ QualType PCHReader::GetType(pch::TypeID ID) {
case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
+ case pch::PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
}
assert(!T.isNull() && "Unknown predefined type");
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 4b9ca5c41a..fc6aa4709e 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -1837,6 +1837,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
case BuiltinType::Float: ID = pch::PREDEF_TYPE_FLOAT_ID; break;
case BuiltinType::Double: ID = pch::PREDEF_TYPE_DOUBLE_ID; break;
case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break;
+ case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break;
case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 509aa0f6d9..bfbac3ac26 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -430,6 +430,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
/// constant
/// string-literal
/// [C++] boolean-literal [C++ 2.13.5]
+/// [C++0x] 'nullptr' [C++0x 2.14.7]
/// '(' expression ')'
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
@@ -569,6 +570,9 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_false:
return ParseCXXBoolLiteral();
+ case tok::kw_nullptr:
+ return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
+
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 30540287eb..20d1edb269 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1534,6 +1534,9 @@ public:
virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
tok::TokenKind Kind);
+ /// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
+ virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc);
+
//// ActOnCXXThrow - Parse throw expressions.
virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc,
ExprArg expr);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 063e0ec314..d2e84c10e2 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3811,6 +3811,20 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
ImpCastExprToType(rex, lType); // promote the pointer to pointer
return ResultTy;
}
+ // C++ allows comparison of pointers with null pointer constants.
+ if (getLangOptions().CPlusPlus) {
+ if (lType->isPointerType() && RHSIsNull) {
+ ImpCastExprToType(rex, lType);
+ return ResultTy;
+ }
+ if (rType->isPointerType() && LHSIsNull) {
+ ImpCastExprToType(lex, rType);
+ return ResultTy;
+ }
+ // And comparison of nullptr_t with itself.
+ if (lType->isNullPtrType() && rType->isNullPtrType())
+ return ResultTy;
+ }
// Handle block pointer types.
if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 92df67aa47..5f2b705498 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -85,6 +85,12 @@ Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
Context.BoolTy, OpLoc));
}
+/// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
+Action::OwningExprResult
+Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
+ return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
+}
+
/// ActOnCXXThrow - Parse throw expressions.
Action::OwningExprResult
Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprArg E) {
diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp
index f5bef4a1f2..e0b94a49ad 100644
--- a/lib/Sema/SemaNamedCast.cpp
+++ b/lib/Sema/SemaNamedCast.cpp
@@ -279,12 +279,26 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return;
}
+ // See below for the enumeral issue.
+ if (SrcType->isNullPtrType() && DestType->isIntegralType() &&
+ !DestType->isEnumeralType()) {
+ // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral
+ // type large enough to hold it. A value of std::nullptr_t can be
+ // converted to an integral type; the conversion has the same meaning
+ // and validity as a conversion of (void*)0 to the integral type.
+ if (Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
+ << OrigDestType << DestRange;
+ }
+ return;
+ }
+
bool destIsPtr = DestType->isPointerType();
bool srcIsPtr = SrcType->isPointerType();
if (!destIsPtr && !srcIsPtr) {
- // Except for std::nullptr_t->integer, which is not supported yet, and
- // lvalue->reference, which is handled above, at least one of the two
- // arguments must be a pointer.
+ // Except for std::nullptr_t->integer and lvalue->reference, which are
+ // handled above, at least one of the two arguments must be a pointer.
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
<< "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
return;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index e6b8056a42..50330e3f63 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -621,7 +621,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
FromType->isEnumeralType() ||
FromType->isPointerType() ||
FromType->isBlockPointerType() ||
- FromType->isMemberPointerType())) {
+ FromType->isMemberPointerType() ||
+ FromType->isNullPtrType())) {
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
}
@@ -898,6 +899,13 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
return true;
}
+ // If the left-hand-side is nullptr_t, the right side can be a null
+ // pointer constant.
+ if (ToType->isNullPtrType() && From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
const PointerType* ToTypePtr = ToType->getAsPointerType();
if (!ToTypePtr)
return false;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index e62b9a26c0..c8fdc220d0 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1198,6 +1198,10 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
if (ImplicitCastExpr *Cast = dyn_cast(Arg))
Arg = Cast->getSubExpr();
+ // C++0x allows nullptr, and there's no further checking to be done for that.
+ if (Arg->getType()->isNullPtrType())
+ return false;
+
// C++ [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template
@@ -1296,6 +1300,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
if (ImplicitCastExpr *Cast = dyn_cast(Arg))
Arg = Cast->getSubExpr();
+ // C++0x allows nullptr, and there's no further checking to be done for that.
+ if (Arg->getType()->isNullPtrType())
+ return false;
+
// C++ [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template
@@ -1485,6 +1493,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// applied. If the template-argument represents a set of
// overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
+ // In C++0x, any std::nullptr_t value can be converted.
(ParamType->isPointerType() &&
ParamType->getAsPointerType()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
@@ -1498,12 +1507,17 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// template-argument represents a set of overloaded member
// functions, the matching member function is selected from
// the set (13.4).
+ // Again, C++0x allows a std::nullptr_t value.
(ParamType->isMemberPointerType() &&
ParamType->getAsMemberPointerType()->getPointeeType()
->isFunctionType())) {
if (Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We don't have to do anything: the types already match.
+ } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
+ ParamType->isMemberPointerType())) {
+ ArgType = ParamType;
+ ImpCastExprToType(Arg, ParamType);
} else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
ArgType = Context.getPointerType(ArgType);
ImpCastExprToType(Arg, ArgType);
@@ -1554,14 +1568,18 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- for a non-type template-parameter of type pointer to
// object, qualification conversions (4.4) and the
// array-to-pointer conversion (4.2) are applied.
+ // C++0x also allows a value of std::nullptr_t.
assert(ParamType->getAsPointerType()->getPointeeType()->isObjectType() &&
"Only object pointers allowed here");
- if (ArgType->isArrayType()) {
+ if (ArgType->isNullPtrType()) {
+ ArgType = ParamType;
+ ImpCastExprToType(Arg, ParamType);
+ } else if (ArgType->isArrayType()) {
ArgType = Context.getArrayDecayedType(ArgType);
ImpCastExprToType(Arg, ArgType);
}
-
+
if (IsQualificationConversion(ArgType, ParamType)) {
ArgType = ParamType;
ImpCastExprToType(Arg, ParamType);
@@ -1630,10 +1648,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- For a non-type template-parameter of type pointer to data
// member, qualification conversions (4.4) are applied.
+ // C++0x allows std::nullptr_t values.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
// Types match exactly: nothing more to do here.
+ } else if (ArgType->isNullPtrType()) {
+ ImpCastExprToType(Arg, ParamType);
} else if (IsQualificationConversion(ArgType, ParamType)) {
ImpCastExprToType(Arg, ParamType);
} else {
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
new file mode 100644
index 0000000000..6cc5a81683
--- /dev/null
+++ b/test/SemaCXX/nullptr.cpp
@@ -0,0 +1,67 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+#include
+
+// Don't have decltype yet.
+typedef __typeof__(nullptr) nullptr_t;
+
+struct A {};
+
+int o1(char*);
+void o1(uintptr_t);
+void o2(char*); // expected-note {{candidate}}
+void o2(int A::*); // expected-note {{candidate}}
+
+nullptr_t f(nullptr_t null)
+{
+ // Implicit conversions.
+ null = nullptr;
+ void *p = nullptr;
+ p = null;
+ int *pi = nullptr;
+ pi = null;
+ null = 0;
+ int A::*pm = nullptr;
+ pm = null;
+ void (*pf)() = nullptr;
+ pf = null;
+ void (A::*pmf)() = nullptr;
+ pmf = null;
+ bool b = nullptr;
+
+ // Can't convert nullptr to integral implicitly.
+ uintptr_t i = nullptr; // expected-error {{incompatible type initializing}}
+
+ // Operators
+ (void)(null == nullptr);
+ (void)(null <= nullptr);
+ (void)(null == (void*)0);
+ (void)((void*)0 == nullptr);
+ (void)(null <= (void*)0);
+ (void)((void*)0 <= nullptr);
+ (void)(1 > nullptr); // expected-error {{invalid operands to binary expression}}
+ (void)(1 != nullptr); // expected-error {{invalid operands to binary expression}}
+ (void)(1 + nullptr); // expected-error {{invalid operands to binary expression}}
+ (void)(0 ? nullptr : 0); // expected-error {{incompatible operand types}}
+ (void)(0 ? nullptr : (void*)0);
+
+ // Overloading
+ int t = o1(nullptr);
+ t = o1(null);
+ o2(nullptr); // expected-error {{ambiguous}}
+
+ // nullptr is an rvalue, null is an lvalue
+ (void)&nullptr; // expected-error {{address expression must be an lvalue}}
+ nullptr_t *pn = &null;
+
+ // You can reinterpret_cast nullptr to an integer.
+ (void)reinterpret_cast(nullptr);
+
+ // You can throw nullptr.
+ throw nullptr;
+}
+
+// Template arguments can be nullptr.
+template
+struct T {};
+
+typedef T NT;
diff --git a/www/cxx_status.html b/www/cxx_status.html
index b165b9b1da..f4b799d668 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -1952,38 +1952,46 @@ welcome!
E [extendid] | | | | | |
C++0x Features |
-
+
+
Explicit conversion operators (N2437) |
✓ |
|
|
|
No name mangling; ASTs don't contain calls to conversion operators |
-
-
+
+
Static assertions (N1720) |
✓ |
✓ |
✓ |
N/A |
|
-
-
+
+
Deleted functions (N2346) |
✓ |
✓ |
✓ |
N/A |
|
-
-
+
+
Rvalue references (N2118 + N2831) |
✓ |
✓ |
✓ |
|
|
-
+
+
+ nullptr (N2431) |
+ ✓ |
+ ✓ |
+ ✓ |
+ |
+ |