From aaffbf7c790a324ed114184db771aae2d2e9151c Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Mon, 14 Jan 2008 02:53:34 +0000 Subject: [PATCH] Rewrite Expr::isNullPointerConstant() to deal with multiple levels of explicit casts. Now, isNullPointerConstant() will return true for the following: "(void*)(double*)0" git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45951 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Expr.cpp | 48 ++++++++++++++++++++++-------------- test/Sema/conditional-expr.c | 12 ++++++--- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 61b02c3e71..61e997da27 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -929,37 +929,47 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, return true; } +/// Helper function for isNullPointerConstant. This routine skips all +/// explicit casts, implicit casts and paren expressions. +const Expr * getNullPointerConstantExpr(const Expr *exp) { + if (const CastExpr *CE = dyn_cast(exp)) { + return getNullPointerConstantExpr(CE->getSubExpr()); + } else if (const ImplicitCastExpr *ICE = dyn_cast(exp)) { + return getNullPointerConstantExpr(ICE->getSubExpr()); + } else if (const ParenExpr *PE = dyn_cast(exp)) { + // Accept ((void*)0) as a null pointer constant, as many other + // implementations do. + return getNullPointerConstantExpr(PE->getSubExpr()); + } + return exp; +} /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an /// integer constant expression with the value zero, or if this is one that is /// cast to void*. bool Expr::isNullPointerConstant(ASTContext &Ctx) const { - // Strip off a cast to void*, if it exists. - if (const CastExpr *CE = dyn_cast(this)) { - // Check that it is a cast to void*. + const CastExpr *CE = dyn_cast(this); + const Expr *e = getNullPointerConstantExpr(this); + + if (CE) { + bool castToVoidStar = false; + // Check if the highest precedence cast is "void *". if (const PointerType *PT = dyn_cast(CE->getType())) { QualType Pointee = PT->getPointeeType(); - if (Pointee.getQualifiers() == 0 && Pointee->isVoidType() && // to void* - CE->getSubExpr()->getType()->isIntegerType()) // from int. - return CE->getSubExpr()->isNullPointerConstant(Ctx); + if (Pointee.getQualifiers() == 0 && Pointee->isVoidType()) + castToVoidStar = true; } - } else if (const ImplicitCastExpr *ICE = dyn_cast(this)) { - // Ignore the ImplicitCastExpr type entirely. - return ICE->getSubExpr()->isNullPointerConstant(Ctx); - } else if (const ParenExpr *PE = dyn_cast(this)) { - // Accept ((void*)0) as a null pointer constant, as many other - // implementations do. - return PE->getSubExpr()->isNullPointerConstant(Ctx); - } - - // This expression must be an integer type. - if (!getType()->isIntegerType()) + // This cast must be an integer type or void *. + if (!CE->getType()->isIntegerType() && !castToVoidStar) + return false; + } else if (!e->getType()->isIntegerType()) { + // This expression must be an integer type. return false; - + } // If we have an integer constant expression, we need to *evaluate* it and // test for the value 0. llvm::APSInt Val(32); - return isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0; + return e->isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0; } unsigned OCUVectorElementExpr::getNumElements() const { diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c index 87fe2d2ed6..24e71153f1 100644 --- a/test/Sema/conditional-expr.c +++ b/test/Sema/conditional-expr.c @@ -1,17 +1,21 @@ // RUN: clang -fsyntax-only -verify -pedantic %s void foo() { *(0 ? (double *)0 : (void *)0) = 0; - *((void *) 0) = 0; // -expected-error {{incomplete type 'void' is not assignable}} + *(0 ? (double *)0 : (void *)(int *)0) = 0; + *(0 ? (double *)0 : (void *)(double *)0) = 0; + *(0 ? (double *)0 : (int *)(void *)0) = 0; // expected-warning {{pointer type mismatch ('double *' and 'int *')}} + *(0 ? (double *)0 : (double *)(void *)0) = 0; + *((void *) 0) = 0; // expected-error {{incomplete type 'void' is not assignable}} double *dp; int *ip; void *vp; dp = vp; vp = dp; - ip = dp; // -expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}} - dp = ip; // -expected-warning {{incompatible pointer types assigning 'int *', expected 'double *'}} + ip = dp; // expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}} + dp = ip; // expected-warning {{incompatible pointer types assigning 'int *', expected 'double *'}} dp = 0 ? (double *)0 : (void *)0; vp = 0 ? (double *)0 : (void *)0; - ip = 0 ? (double *)0 : (void *)0; // -expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}} + ip = 0 ? (double *)0 : (void *)0; // expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}} }