QualType UnsignedLongLongTy, UnsignedInt128Ty;
QualType FloatTy, DoubleTy, LongDoubleTy;
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
- QualType VoidPtrTy;
+ QualType VoidPtrTy, NullPtrTy;
QualType OverloadTy;
QualType DependentTy;
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.
STMT(CXXFunctionalCastExpr , ExplicitCastExpr)
STMT(CXXTypeidExpr , Expr)
STMT(CXXBoolLiteralExpr , Expr)
+STMT(CXXNullPtrLiteralExpr , Expr)
STMT(CXXThisExpr , Expr)
STMT(CXXThrowExpr , Expr)
STMT(CXXDefaultArgExpr , Expr)
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
/// 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
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.
};
inline bool Type::hasPointerRepresentation() const {
return (isPointerType() || isReferenceType() || isBlockPointerType() ||
isObjCInterfaceType() || isObjCQualifiedIdType() ||
- isObjCQualifiedInterfaceType());
+ isObjCQualifiedInterfaceType() || isNullPtrType());
}
inline bool Type::hasObjCPointerRepresentation() const {
/// \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
/// 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();
}
// void * type
VoidPtrTy = getPointerType(VoidTy);
+
+ // nullptr type (C++0x 2.14.7)
+ InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
}
//===----------------------------------------------------------------------===//
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:
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;
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(); }
{ 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
OS << (Node->getValue() ? "true" : "false");
}
+void StmtPrinter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) {
+ OS << "nullptr";
+}
+
void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
OS << "this";
}
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!");
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>";
}
// 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;
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:
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");
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;
}
/// 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__'
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
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);
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();
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) {
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;
FromType->isEnumeralType() ||
FromType->isPointerType() ||
FromType->isBlockPointerType() ||
- FromType->isMemberPointerType())) {
+ FromType->isMemberPointerType() ||
+ FromType->isNullPtrType())) {
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
}
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;
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
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
// 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
// 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);
// -- 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);
// -- 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 {
--- /dev/null
+// 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;
<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">✓</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">✓</td>
<td class="complete" align="center">✓</td>
<td class="complete" align="center">✓</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">✓</td>
<td class="complete" align="center">✓</td>
<td class="complete" align="center">✓</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">✓</td>
<td class="complete" align="center">✓</td>
<td class="complete" align="center">✓</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">✓</td>
+ <td class="complete" align="center">✓</td>
+ <td class="complete" align="center">✓</td>
+ <td class="broken"></td>
+ <td></td>
</tr>
</table>