"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">;
"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<
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.
- (id) foo {
if (self)
return self;
- *((int *) 0x0) = 0xDEADBEEF; // no-warning
+ *((volatile int *) 0x0) = 0xDEADBEEF; // no-warning
return self;
}
@end
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.
+}
+