implement PR7569, warning about assignment to null, which

people seem to write when they want a deterministic trap.
Suggest instead that they use a volatile pointer or 
__builtin_trap.

llvm-svn: 107756
This commit is contained in:
Chris Lattner 2010-07-07 06:14:23 +00:00
parent 11086fcb65
commit 3956106543
4 changed files with 31 additions and 7 deletions

View File

@ -21,12 +21,6 @@ def ext_expr_not_ice : Extension<
"expression is not integer constant expression "
"(but is allowed as an extension)">;
def ext_null_pointer_expr_not_ice : Extension<
"null pointer expression is not an integer constant expression "
"(but is allowed as an extension)">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
"predefined identifier is only valid inside function">;
@ -2095,6 +2089,11 @@ def err_typecheck_unary_expr : Error<
"invalid argument type %0 to unary expression">;
def err_typecheck_indirection_requires_pointer : Error<
"indirection requires pointer operand (%0 invalid)">;
def warn_indirection_through_null : Warning<
"indirection of non-volatile null pointer will be deleted, not trap">;
def note_indirection_through_null : Note<
"consider using __builtin_trap() or qualifying pointer with 'volatile'">;
def err_indirection_requires_nonfragile_object : Error<
"indirection cannot be to an interface in non-fragile ABI (%0 invalid)">;
def err_direct_interface_unsupported : Error<

View File

@ -5892,6 +5892,23 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
RHS, AA_Assigning))
return QualType();
// Check to see if the destination operand is a dereferenced null pointer. If
// so, and if not volatile-qualified, this is undefined behavior that the
// optimizer will delete, so warn about it. People sometimes try to use this
// to get a deterministic trap and are surprised by clang's behavior. This
// only handles the pattern "*null = whatever", which is a very syntactic
// check.
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS->IgnoreParenCasts()))
if (UO->getOpcode() == UnaryOperator::Deref &&
UO->getSubExpr()->IgnoreParenCasts()->
isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) &&
!UO->getType().isVolatileQualified()) {
Diag(UO->getOperatorLoc(), diag::warn_indirection_through_null)
<< UO->getSubExpr()->getSourceRange();
Diag(UO->getOperatorLoc(), diag::note_indirection_through_null);
}
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
// it is the unqualified version of the type of the left operand.

View File

@ -582,7 +582,7 @@ void pr4781(unsigned long *raw1) {
- (id) foo {
if (self)
return self;
*((int *) 0x0) = 0xDEADBEEF; // no-warning
*((volatile int *) 0x0) = 0xDEADBEEF; // no-warning
return self;
}
@end

View File

@ -134,3 +134,11 @@ void test18(int b) {
test18_a(b, b); // expected-error {{too many arguments to function call, expected 1, have 2}}
test18_a(); // expected-error {{too few arguments to function call, expected 1, have 0}}
}
// PR7569
void test19() {
*(int*)0 = 0; // expected-warning {{indirection of non-volatile null pointer}} \
// expected-note {{consider using __builtin_trap}}
*(volatile int*)0 = 0; // Ok.
}