Implement C++0x nullptr.

llvm-svn: 71405
This commit is contained in:
Sebastian Redl 2009-05-10 18:38:11 +00:00
parent 9a627e60cd
commit 576fd424df
24 changed files with 230 additions and 20 deletions

View File

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

View File

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

View File

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

View File

@ -394,6 +394,7 @@ public:
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
bool isObjCQualifiedIdType() const; // id<foo>
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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 "<overloaded function type>";
case Dependent: return "<dependent type>";
}

View File

@ -499,6 +499,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// UNSUPPORTED: ::= Di # char32_t
// UNSUPPORTED: ::= Ds # char16_t
// ::= u <source-name> # 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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1198,6 +1198,10 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(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<ImplicitCastExpr>(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 {

View File

@ -0,0 +1,67 @@
// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
#include <stdint.h>
// 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<uintptr_t>(nullptr);
// You can throw nullptr.
throw nullptr;
}
// Template arguments can be nullptr.
template <int *PI, void (*PF)(), int A::*PM, void (A::*PMF)()>
struct T {};
typedef T<nullptr, nullptr, nullptr, nullptr> NT;

View File

@ -1952,38 +1952,46 @@ welcome!</p>
<tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
<td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
<tr>
</tr>
<tr>
<td>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>)</td>
<td class="complete" align="center">&#x2713;</td>
<td class="medium" align="center"></td>
<td class="advanced" align="center"></td>
<td class="broken"></td>
<td>No name mangling; ASTs don't contain calls to conversion operators</td>
</tr>
<tr>
</tr>
<tr>
<td>Static assertions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.pdf">N1720</a>)</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="na">N/A</td>
<td></td>
</tr>
<tr>
</tr>
<tr>
<td>Deleted functions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">N2346</a>)</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="na">N/A</td>
<td></td>
</tr>
<tr>
</tr>
<tr>
<td>Rvalue references (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html">N2118</a> + <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2831.html">N2831</a>)</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="broken"></td>
<td></td>
</tr>
</tr>
<tr>
<td>nullptr (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf">N2431</a>)</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="broken"></td>
<td></td>
</tr>
</table>