From: Steve Naroff Date: Thu, 16 Aug 2007 21:48:38 +0000 (+0000) Subject: Fixed Sema::CheckEqualityOperands() and Sema::CheckRelationalOperands() to deal more X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e77fd3c15c8c4a2f1225e75d5742b6ad07578913;p=clang Fixed Sema::CheckEqualityOperands() and Sema::CheckRelationalOperands() to deal more thoughtfully with incompatible pointers. This includes: - Emit a diagnostic when two pointers aren't compatible! - Promote one of the pointers/integers so we maintain the invariant expected by the code generator (i.e. that the left/right types match). - Upgrade the pointer/integer comparison diagnostic to include the types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41127 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index f69867fdf1..43e06867c6 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1047,22 +1047,34 @@ inline QualType Sema::CheckRelationalOperands( // C99 6.5.8 if (lType->isRealType() && rType->isRealType()) return Context.IntTy; - if (lType->isPointerType()) { - if (rType->isPointerType()) - return Context.IntTy; - if (rType->isIntegerType()) { - if (!rex->isNullPointerConstant(Context)) - Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, - lex->getSourceRange(), rex->getSourceRange()); - return Context.IntTy; // the previous diagnostic is a GCC extension. + // All of the following pointer related warnings are GCC extensions. One + // day, we can consider making them errors (when -pedantic-errors is enabled). + if (lType->isPointerType() && rType->isPointerType()) { + if (!Type::pointerTypesAreCompatible(lType, rType)) { + Diag(loc, diag::ext_typecheck_comparison_of_distinct_pointers, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + promoteExprToType(rex, lType); // promote the pointer to pointer } - } else if (rType->isPointerType()) { - if (lType->isIntegerType()) { - if (!lex->isNullPointerConstant(Context)) - Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, - lex->getSourceRange(), rex->getSourceRange()); - return Context.IntTy; // the previous diagnostic is a GCC extension. + return Context.IntTy; + } + if (lType->isPointerType() && rType->isIntegerType()) { + if (!rex->isNullPointerConstant(Context)) { + Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + promoteExprToType(rex, lType); // promote the integer to pointer } + return Context.IntTy; + } + if (lType->isIntegerType() && rType->isPointerType()) { + if (!lex->isNullPointerConstant(Context)) { + Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + promoteExprToType(lex, rType); // promote the integer to pointer + } + return Context.IntTy; } InvalidOperands(loc, lex, rex); return QualType(); @@ -1084,22 +1096,34 @@ inline QualType Sema::CheckEqualityOperands( // C99 6.5.9 if (lType->isArithmeticType() && rType->isArithmeticType()) return Context.IntTy; - if (lType->isPointerType()) { - if (rType->isPointerType()) - return Context.IntTy; - if (rType->isIntegerType()) { - if (!rex->isNullPointerConstant(Context)) - Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, - lex->getSourceRange(), rex->getSourceRange()); - return Context.IntTy; // the previous diagnostic is a GCC extension. + // All of the following pointer related warnings are GCC extensions. One + // day, we can consider making them errors (when -pedantic-errors is enabled). + if (lType->isPointerType() && rType->isPointerType()) { + if (!Type::pointerTypesAreCompatible(lType, rType)) { + Diag(loc, diag::ext_typecheck_comparison_of_distinct_pointers, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + promoteExprToType(rex, lType); // promote the pointer to pointer } - } else if (rType->isPointerType()) { - if (lType->isIntegerType()) { - if (!lex->isNullPointerConstant(Context)) - Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, - lex->getSourceRange(), rex->getSourceRange()); - return Context.IntTy; // the previous diagnostic is a GCC extension. + return Context.IntTy; + } + if (lType->isPointerType() && rType->isIntegerType()) { + if (!rex->isNullPointerConstant(Context)) { + Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + promoteExprToType(rex, lType); // promote the integer to pointer } + return Context.IntTy; + } + if (lType->isIntegerType() && rType->isPointerType()) { + if (!lex->isNullPointerConstant(Context)) { + Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + promoteExprToType(lex, rType); // promote the integer to pointer + } + return Context.IntTy; } InvalidOperands(loc, lex, rex); return QualType(); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 9137a8419f..e13a95bac0 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -611,7 +611,9 @@ DIAG(ext_typecheck_deref_ptr_to_void, WARNING, DIAG(err_typecheck_invalid_operands, ERROR, "invalid operands to binary expression ('%0' and '%1')") DIAG(ext_typecheck_comparison_of_pointer_integer, WARNING, - "comparison between pointer and integer") + "comparison between pointer and integer ('%0' and '%1')") +DIAG(ext_typecheck_comparison_of_distinct_pointers, WARNING, + "comparison of distinct pointer types ('%0' and '%1')") DIAG(err_typecheck_assign_const, ERROR, "read-only variable is not assignable") DIAG(err_typecheck_assign_incompatible, ERROR, diff --git a/test/Parser/pointer_promotion.c b/test/Parser/pointer_promotion.c new file mode 100644 index 0000000000..18cd9687b7 --- /dev/null +++ b/test/Parser/pointer_promotion.c @@ -0,0 +1,18 @@ +// RUN: clang -parse-ast-check %s + +int test() { + void *vp; + int *ip; + char *cp; + struct foo *fp; + struct bar *bp; + short sint = 7; + + if (ip < cp) ; // expected-warning {{comparison of distinct pointer types ('int *' and 'char *')}} + if (cp < fp) ; // expected-warning {{comparison of distinct pointer types ('char *' and 'struct foo *')}} + if (fp < bp) ; // expected-warning {{comparison of distinct pointer types ('struct foo *' and 'struct bar *')}} + if (ip < 7) ; // expected-warning {{comparison between pointer and integer ('int *' and 'int')}} + if (sint < ip) ; // expected-warning {{comparison between pointer and integer ('int' and 'int *')}} + if (ip == cp) ; // expected-warning {{comparison of distinct pointer types ('int *' and 'char *')}} +} +