From: Douglas Gregor Date: Sat, 29 Nov 2008 04:51:27 +0000 (+0000) Subject: Implement the GNU __null extension X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2d8b273470684a9cd47f0ce24743cc1f71ef7cbc;p=clang Implement the GNU __null extension git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60235 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 321dca5336..dfdca82c74 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1295,7 +1295,7 @@ public: /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. /// This AST node is similar to the conditional operator (?:) in C, with /// the following exceptions: -/// - the test expression much be a constant expression. +/// - the test expression must be a constant expression. /// - the expression returned has it's type unaltered by promotion rules. /// - does not evaluate the expression that was not chosen. class ChooseExpr : public Expr { @@ -1336,6 +1336,39 @@ public: static ChooseExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C); }; +/// GNUNullExpr - Implements the GNU __null extension, which is a name +/// for a null pointer constant that has integral type (e.g., int or +/// long) and is the same size and alignment as a pointer. The __null +/// extension is typically only used by system headers, which define +/// NULL as __null in C++ rather than using 0 (which is an integer +/// that may not match the size of a pointer). +class GNUNullExpr : public Expr { + /// TokenLoc - The location of the __null keyword. + SourceLocation TokenLoc; + +public: + GNUNullExpr(QualType Ty, SourceLocation Loc) + : Expr(GNUNullExprClass, Ty), TokenLoc(Loc) { } + + /// getTokenLocation - The location of the __null token. + SourceLocation getTokenLocation() const { return TokenLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TokenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GNUNullExprClass; + } + static bool classof(const GNUNullExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + virtual void EmitImpl(llvm::Serializer& S) const; + static GNUNullExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C); +}; + /// OverloadExpr - Clang builtin function __builtin_overload. /// This AST node provides a way to overload functions in C. /// diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 06e5419d9e..0c7faff1ed 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -88,6 +88,7 @@ STMT(AddrLabelExpr , Expr) STMT(StmtExpr , Expr) STMT(TypesCompatibleExpr , Expr) STMT(ChooseExpr , Expr) +STMT(GNUNullExpr , Expr) // C++ Expressions. STMT(CXXOperatorCallExpr , CallExpr) diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index e32dc388fc..cf18b6250d 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -638,6 +638,12 @@ public: return 0; } + /// ActOnGNUNullExpr - Parsed the GNU __null expression, the token + /// for which is at position TokenLoc. + virtual ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) { + return 0; + } + //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 7a8119c5e3..3c021c262d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1031,8 +1031,11 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const { = dyn_cast(this)) { // See through default argument expressions return DefaultArg->getExpr()->isNullPointerConstant(Ctx); + } else if (isa(this)) { + // The GNU __null extension is always a null pointer constant. + return true; } - + // This expression must be an integer type. if (!getType()->isIntegerType()) return false; @@ -1383,6 +1386,10 @@ Stmt::child_iterator TypesCompatibleExpr::child_end() { Stmt::child_iterator ChooseExpr::child_begin() { return &SubExprs[0]; } Stmt::child_iterator ChooseExpr::child_end() { return &SubExprs[0]+END_EXPR; } +// GNUNullExpr +Stmt::child_iterator GNUNullExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator GNUNullExpr::child_end() { return child_iterator(); } + // OverloadExpr Stmt::child_iterator OverloadExpr::child_begin() { return &SubExprs[0]; } Stmt::child_iterator OverloadExpr::child_end() { return &SubExprs[0]+NumExprs; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index fcebdab05c..b6f0707053 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -783,6 +783,10 @@ void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { OS << ")"; } +void StmtPrinter::VisitGNUNullExpr(GNUNullExpr *) { + OS << "__null"; +} + void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) { OS << "__builtin_overload("; for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 8bf7039685..3cf1f5497f 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -61,6 +61,9 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) { case CharacterLiteralClass: return CharacterLiteral::CreateImpl(D, C); + case ChooseExprClass: + return ChooseExpr::CreateImpl(D, C); + case CompoundAssignOperatorClass: return CompoundAssignOperator::CreateImpl(D, C); @@ -94,6 +97,9 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) { case ForStmtClass: return ForStmt::CreateImpl(D, C); + case GNUNullExprClass: + return GNUNullExpr::CreateImpl(D, C); + case GotoStmtClass: return GotoStmt::CreateImpl(D, C); @@ -904,6 +910,17 @@ ChooseExpr* ChooseExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) { return CE; } +void GNUNullExpr::EmitImpl(llvm::Serializer &S) const { + S.Emit(getType()); + S.Emit(TokenLoc); +} + +GNUNullExpr *GNUNullExpr::CreateImpl(llvm::Deserializer &D, ASTContext &C) { + QualType T = QualType::ReadVal(D); + SourceLocation TL = SourceLocation::ReadVal(D); + return new GNUNullExpr(T, TL); +} + void OverloadExpr::EmitImpl(llvm::Serializer& S) const { S.Emit(getType()); S.Emit(BuiltinLoc); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 66b1d18078..df46612b57 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -378,6 +378,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' /// [OBJC] '@selector' '(' objc-selector-arg ')' /// [OBJC] '@protocol' '(' identifier ')' @@ -531,6 +532,9 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::kw___builtin_overload: case tok::kw___builtin_types_compatible_p: return ParseBuiltinPrimaryExpression(); + case tok::kw___null: + return Actions.ActOnGNUNullExpr(ConsumeToken()); + break; case tok::plusplus: // unary-expression: '++' unary-expression case tok::minusminus: { // unary-expression: '--' unary-expression SourceLocation SavedLoc = ConsumeToken(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 57caa6ecf2..044bfbd73b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -736,6 +736,9 @@ public: ExprTy *expr, TypeTy *type, SourceLocation RPLoc); + // __null + virtual ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); + //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e21047e10d..fb964692b3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3603,6 +3603,18 @@ Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, return new VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(), RPLoc); } +Sema::ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { + // The type of __null will be int or long, depending on the size of + // pointers on the target. + QualType Ty; + if (Context.Target.getPointerWidth(0) == Context.Target.getIntWidth()) + Ty = Context.IntTy; + else + Ty = Context.LongTy; + + return new GNUNullExpr(Ty, TokenLoc); +} + bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType,