[cfe-commits] r82748 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/Analysis/CheckObjCDealloc.cpp lib/Sema/Sema.h lib/Sema/SemaChecking.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp test/SemaTemplate/value-dependent-null-pointer-constant.cpp

Douglas Gregor dgregor at apple.com
Thu Sep 24 21:25:59 PDT 2009


Author: dgregor
Date: Thu Sep 24 23:25:58 2009
New Revision: 82748

URL: http://llvm.org/viewvc/llvm-project?rev=82748&view=rev
Log:
Fix checking for a null pointer constant when the expression itself is
value-dependent. Audit (and fixed) all calls to
Expr::isNullPointerConstant() to provide the correct behavior with
value-dependent expressions. Fixes PR5041 and a crash in libstdc++
<locale>.

In the same vein, properly compute value- and type-dependence for
ChooseExpr. Fixes PR4996.


Added:
    cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Thu Sep 24 23:25:58 2009
@@ -257,10 +257,26 @@
   /// also succeeds on stack based, immutable address lvalues.
   bool EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const;
 
+  /// \brief Enumeration used to describe how \c isNullPointerConstant()
+  /// should cope with value-dependent expressions.
+  enum NullPointerConstantValueDependence {
+    /// \brief Specifies that the expression should never be value-dependent.
+    NPC_NeverValueDependent = 0,
+    
+    /// \brief Specifies that a value-dependent expression of integral or
+    /// dependent type should be considered a null pointer constant.
+    NPC_ValueDependentIsNull,
+    
+    /// \brief Specifies that a value-dependent expression should be considered
+    /// to never be a null pointer constant.
+    NPC_ValueDependentIsNotNull
+  };
+  
   /// 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 isNullPointerConstant(ASTContext &Ctx) const;
+  bool isNullPointerConstant(ASTContext &Ctx,
+                             NullPointerConstantValueDependence NPC) const;
 
   /// isOBJCGCCandidate - Return true if this expression may be used in a read/
   /// write barrier.
@@ -2004,8 +2020,8 @@
   SourceLocation BuiltinLoc, RParenLoc;
 public:
   ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t,
-             SourceLocation RP)
-    : Expr(ChooseExprClass, t),
+             SourceLocation RP, bool TypeDependent, bool ValueDependent)
+    : Expr(ChooseExprClass, t, TypeDependent, ValueDependent),
       BuiltinLoc(BLoc), RParenLoc(RP) {
       SubExprs[COND] = cond;
       SubExprs[LHS] = lhs;

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Thu Sep 24 23:25:58 2009
@@ -1625,9 +1625,21 @@
 /// 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 {
-  // Ignore value dependent expressions.
-  assert(!isValueDependent() && "Unexpect value dependent expression!");
+bool Expr::isNullPointerConstant(ASTContext &Ctx,
+                                 NullPointerConstantValueDependence NPC) const {
+  if (isValueDependent()) {
+    switch (NPC) {
+    case NPC_NeverValueDependent:
+      assert(false && "Unexpected value dependent expression!");
+      // If the unthinkable happens, fall through to the safest alternative.
+        
+    case NPC_ValueDependentIsNull:
+      return isTypeDependent() || getType()->isIntegralType();
+        
+    case NPC_ValueDependentIsNotNull:
+      return false;
+    }
+  }
 
   // Strip off a cast to void*, if it exists. Except in C++.
   if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) {
@@ -1638,20 +1650,20 @@
         if (!Pointee.hasQualifiers() &&
             Pointee->isVoidType() &&                              // to void*
             CE->getSubExpr()->getType()->isIntegerType())         // from int.
-          return CE->getSubExpr()->isNullPointerConstant(Ctx);
+          return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
       }
     }
   } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) {
     // Ignore the ImplicitCastExpr type entirely.
-    return ICE->getSubExpr()->isNullPointerConstant(Ctx);
+    return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
   } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) {
     // Accept ((void*)0) as a null pointer constant, as many other
     // implementations do.
-    return PE->getSubExpr()->isNullPointerConstant(Ctx);
+    return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
   } else if (const CXXDefaultArgExpr *DefaultArg
                = dyn_cast<CXXDefaultArgExpr>(this)) {
     // See through default argument expressions
-    return DefaultArg->getExpr()->isNullPointerConstant(Ctx);
+    return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC);
   } else if (isa<GNUNullExpr>(this)) {
     // The GNU __null extension is always a null pointer constant.
     return true;

Modified: cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp (original)
+++ cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp Thu Sep 24 23:25:58 2009
@@ -64,7 +64,8 @@
           if (E->getDecl()->getIdentifier() == SelfII)
             if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
                 ME->getNumArgs() == 1 &&
-                ME->getArg(0)->isNullPointerConstant(Ctx))
+                ME->getArg(0)->isNullPointerConstant(Ctx, 
+                                              Expr::NPC_ValueDependentIsNull))
               return true;
 
   // self.myIvar = nil;
@@ -73,7 +74,8 @@
       if (ObjCPropertyRefExpr* PRE =
          dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
           if (PRE->getProperty() == PD)
-            if (BO->getRHS()->isNullPointerConstant(Ctx)) {
+            if (BO->getRHS()->isNullPointerConstant(Ctx, 
+                                            Expr::NPC_ValueDependentIsNull)) {
               // This is only a 'release' if the property kind is not
               // 'assign'.
               return PD->getSetterKind() != ObjCPropertyDecl::Assign;;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Sep 24 23:25:58 2009
@@ -782,6 +782,7 @@
   bool CheckPointerConversion(Expr *From, QualType ToType, 
                               CastExpr::CastKind &Kind);
   bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
+                                 bool InOverloadResolution,
                                  QualType &ConvertedType);
   bool CheckMemberPointerConversion(Expr *From, QualType ToType,
                                     CastExpr::CastKind &Kind);

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Sep 24 23:25:58 2009
@@ -93,7 +93,7 @@
     unsigned format_idx = Format->getFormatIdx() - 1;
     if (format_idx < TheCall->getNumArgs()) {
       Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
-      if (!Format->isNullPointerConstant(Context))
+      if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
         return true;
     }
   }
@@ -911,7 +911,8 @@
   for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end();
        i != e; ++i) {
     const Expr *ArgExpr = TheCall->getArg(*i);
-    if (ArgExpr->isNullPointerConstant(Context))
+    if (ArgExpr->isNullPointerConstant(Context, 
+                                       Expr::NPC_ValueDependentIsNotNull))
       Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
         << ArgExpr->getSourceRange();
   }

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep 24 23:25:58 2009
@@ -173,7 +173,8 @@
   }
   Expr *sentinelExpr = Args[sentinel];
   if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
-                       !sentinelExpr->isNullPointerConstant(Context))) {
+                       !sentinelExpr->isNullPointerConstant(Context,
+                                            Expr::NPC_ValueDependentIsNull))) {
     Diag(Loc, diag::warn_missing_sentinel) << isMethod;
     Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
   }
@@ -3395,12 +3396,12 @@
   // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
   // the type of the other operand."
   if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
-      RHS->isNullPointerConstant(Context)) {
+      RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
     return LHSTy;
   }
   if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
-      LHS->isNullPointerConstant(Context)) {
+      LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
     return RHSTy;
   }
@@ -3982,7 +3983,8 @@
           break;
         }
 
-      if (rExpr->isNullPointerConstant(Context)) {
+      if (rExpr->isNullPointerConstant(Context, 
+                                       Expr::NPC_ValueDependentIsNull)) {
         ImpCastExprToType(rExpr, it->getType());
         InitField = *it;
         break;
@@ -4025,7 +4027,8 @@
   if ((lhsType->isPointerType() ||
        lhsType->isObjCObjectPointerType() ||
        lhsType->isBlockPointerType())
-      && rExpr->isNullPointerConstant(Context)) {
+      && rExpr->isNullPointerConstant(Context, 
+                                      Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(rExpr, lhsType);
     return Compatible;
   }
@@ -4454,12 +4457,14 @@
     Expr *literalString = 0;
     Expr *literalStringStripped = 0;
     if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
-        !RHSStripped->isNullPointerConstant(Context)) {
+        !RHSStripped->isNullPointerConstant(Context, 
+                                            Expr::NPC_ValueDependentIsNull)) {
       literalString = lex;
       literalStringStripped = LHSStripped;
     } else if ((isa<StringLiteral>(RHSStripped) ||
                 isa<ObjCEncodeExpr>(RHSStripped)) &&
-               !LHSStripped->isNullPointerConstant(Context)) {
+               !LHSStripped->isNullPointerConstant(Context, 
+                                            Expr::NPC_ValueDependentIsNull)) {
       literalString = rex;
       literalStringStripped = RHSStripped;
     }
@@ -4504,8 +4509,10 @@
       return ResultTy;
   }
 
-  bool LHSIsNull = lex->isNullPointerConstant(Context);
-  bool RHSIsNull = rex->isNullPointerConstant(Context);
+  bool LHSIsNull = lex->isNullPointerConstant(Context, 
+                                              Expr::NPC_ValueDependentIsNull);
+  bool RHSIsNull = rex->isNullPointerConstant(Context, 
+                                              Expr::NPC_ValueDependentIsNull);
 
   // All of the following pointer related warnings are GCC extensions, except
   // when handling null pointer constants. One day, we can consider making them
@@ -5721,8 +5728,10 @@
   assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
 
   QualType resType;
+  bool ValueDependent = false;
   if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
     resType = Context.DependentTy;
+    ValueDependent = true;
   } else {
     // The conditional expression is required to be a constant expression.
     llvm::APSInt condEval(32);
@@ -5734,11 +5743,15 @@
 
     // If the condition is > zero, then the AST type is the same as the LSHExpr.
     resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
+    ValueDependent = condEval.getZExtValue() ? LHSExpr->isValueDependent()
+                                             : RHSExpr->isValueDependent();
   }
 
   cond.release(); expr1.release(); expr2.release();
   return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
-                                        resType, RPLoc));
+                                        resType, RPLoc,
+                                        resType->isDependentType(),
+                                        ValueDependent));
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Sep 24 23:25:58 2009
@@ -1648,11 +1648,13 @@
   // frankly, is stupid.)
   const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>();
   const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>();
-  if (LMemPtr && RHS->isNullPointerConstant(Context)) {
+  if (LMemPtr && 
+      RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(RHS, LTy);
     return LTy;
   }
-  if (RMemPtr && LHS->isNullPointerConstant(Context)) {
+  if (RMemPtr && 
+      LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(LHS, RTy);
     return RTy;
   }
@@ -1743,11 +1745,11 @@
   //   pointer operands to bring them to their composite pointer type. If
   //   one operand is a null pointer constant, the composite pointer type is
   //   the type of the other operand.
-  if (E1->isNullPointerConstant(Context)) {
+  if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(E1, T2);
     return T2;
   }
-  if (E2->isNullPointerConstant(Context)) {
+  if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
     ImpCastExprToType(E2, T1);
     return T1;
   }

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=82748&r1=82747&r2=82748&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Sep 24 23:25:58 2009
@@ -633,7 +633,8 @@
     // Pointer conversions (C++ 4.10).
     SCS.Second = ICK_Pointer_Conversion;
     SCS.IncompatibleObjC = IncompatibleObjC;
-  } else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) {
+  } else if (IsMemberPointerConversion(From, FromType, ToType, 
+                                       InOverloadResolution, FromType)) {
     // Pointer to member conversions (4.11).
     SCS.Second = ICK_Pointer_Member;
   } else if (ToType->isBooleanType() &&
@@ -883,7 +884,9 @@
       Expr->getType()->isIntegralType())
     return !InOverloadResolution;
 
-  return Expr->isNullPointerConstant(Context);
+  return Expr->isNullPointerConstant(Context,
+                    InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
+                                        : Expr::NPC_ValueDependentIsNull);
 }
 
 /// IsPointerConversion - Determines whether the conversion of the
@@ -1188,13 +1191,17 @@
 /// If so, returns true and places the converted type (that might differ from
 /// ToType in its cv-qualifiers at some level) into ConvertedType.
 bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
-                                     QualType ToType, QualType &ConvertedType) {
+                                     QualType ToType, 
+                                     bool InOverloadResolution,
+                                     QualType &ConvertedType) {
   const MemberPointerType *ToTypePtr = ToType->getAs<MemberPointerType>();
   if (!ToTypePtr)
     return false;
 
   // A null pointer constant can be converted to a member pointer (C++ 4.11p1)
-  if (From->isNullPointerConstant(Context)) {
+  if (From->isNullPointerConstant(Context,
+                    InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
+                                        : Expr::NPC_ValueDependentIsNull)) {
     ConvertedType = ToType;
     return true;
   }
@@ -1231,7 +1238,8 @@
   const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
   if (!FromPtrType) {
     // This must be a null pointer to member pointer conversion
-    assert(From->isNullPointerConstant(Context) &&
+    assert(From->isNullPointerConstant(Context, 
+                                       Expr::NPC_ValueDependentIsNull) &&
            "Expr must be null pointer constant!");
     Kind = CastExpr::CK_NullToMemberPointer;
     return false;

Added: cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp?rev=82748&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp (added)
+++ cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp Thu Sep 24 23:25:58 2009
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T, int N>
+struct X0 {
+  const char *f0(bool Cond) {
+    return Cond? "honk" : N;
+  }
+
+  const char *f1(bool Cond) {
+    return Cond? N : "honk";
+  }
+  
+  bool f2(const char *str) {
+    return str == N;
+  }
+};
+
+// PR4996
+template<unsigned I> int f0() { 
+  return __builtin_choose_expr(I, 0, 1); 
+}
+
+// PR5041
+struct A { };
+
+template <typename T> void f(T *t)
+{
+  (void)static_cast<void*>(static_cast<A*>(t));
+}
\ No newline at end of file

Propchange: cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaTemplate/value-dependent-null-pointer-constant.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list