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) + ✓ + ✓ + ✓ + +