[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