Skip to content

Commit 0885ce9

Browse files
author
git apple-llvm automerger
committed
Merge commit '6d34cfac53b9' from llvm.org/main into next
2 parents 265cae7 + 6d34cfa commit 0885ce9

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,16 @@ Improvements to Clang's diagnostics
683683
views.push_back(std::string("123")); // warning
684684
}
685685

686+
- Clang now emits a ``-Wtautological-compare`` diagnostic when a check for
687+
pointer addition overflow is always true or false, because overflow would
688+
be undefined behavior.
689+
690+
.. code-block:: c++
691+
692+
bool incorrect_overflow_check(const char *ptr, size_t index) {
693+
return ptr + index < ptr; // warning
694+
}
695+
686696
Improvements to Clang's time-trace
687697
----------------------------------
688698

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10315,7 +10315,7 @@ def warn_dangling_reference_captured_by_unknown : Warning<
1031510315
// should result in a warning, since these always evaluate to a constant.
1031610316
// Array comparisons have similar warnings
1031710317
def warn_comparison_always : Warning<
10318-
"%select{self-|array }0comparison always evaluates to "
10318+
"%select{self-|array |pointer }0comparison always evaluates to "
1031910319
"%select{a constant|true|false|'std::strong_ordering::equal'}1">,
1032010320
InGroup<TautologicalCompare>;
1032110321
def warn_comparison_bitwise_always : Warning<

clang/lib/Sema/SemaExpr.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14753,6 +14753,50 @@ static bool checkForArray(const Expr *E) {
1475314753
return D->getType()->isArrayType() && !D->isWeak();
1475414754
}
1475514755

14756+
/// Detect patterns ptr + size >= ptr and ptr + size < ptr, where ptr is a
14757+
/// pointer and size is an unsigned integer. Return whether the result is
14758+
/// always true/false.
14759+
static std::optional<bool> isTautologicalBoundsCheck(const Expr *LHS,
14760+
const Expr *RHS,
14761+
BinaryOperatorKind Opc) {
14762+
if (!LHS->getType()->isPointerType())
14763+
return std::nullopt;
14764+
14765+
// Canonicalize to >= or < predicate.
14766+
switch (Opc) {
14767+
case BO_GE:
14768+
case BO_LT:
14769+
break;
14770+
case BO_GT:
14771+
std::swap(LHS, RHS);
14772+
Opc = BO_LT;
14773+
break;
14774+
case BO_LE:
14775+
std::swap(LHS, RHS);
14776+
Opc = BO_GE;
14777+
break;
14778+
default:
14779+
return std::nullopt;
14780+
}
14781+
14782+
auto *BO = dyn_cast<BinaryOperator>(LHS);
14783+
if (!BO || BO->getOpcode() != BO_Add)
14784+
return std::nullopt;
14785+
14786+
Expr *Other;
14787+
if (Expr::isSameComparisonOperand(BO->getLHS(), RHS))
14788+
Other = BO->getRHS();
14789+
else if (Expr::isSameComparisonOperand(BO->getRHS(), RHS))
14790+
Other = BO->getLHS();
14791+
else
14792+
return std::nullopt;
14793+
14794+
if (!Other->getType()->isUnsignedIntegerType())
14795+
return std::nullopt;
14796+
14797+
return Opc == BO_GE;
14798+
}
14799+
1475614800
/// Diagnose some forms of syntactically-obvious tautological comparison.
1475714801
static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
1475814802
Expr *LHS, Expr *RHS,
@@ -14862,6 +14906,12 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
1486214906
S.PDiag(diag::warn_comparison_always)
1486314907
<< 1 /*array comparison*/
1486414908
<< Result);
14909+
} else if (std::optional<bool> Res =
14910+
isTautologicalBoundsCheck(LHS, RHS, Opc)) {
14911+
S.DiagRuntimeBehavior(Loc, nullptr,
14912+
S.PDiag(diag::warn_comparison_always)
14913+
<< 2 /*pointer comparison*/
14914+
<< (*Res ? AlwaysTrue : AlwaysFalse));
1486514915
}
1486614916
}
1486714917

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
int add_ptr_idx_ult_ptr(const char *ptr, unsigned index) {
4+
return ptr + index < ptr; // expected-warning {{pointer comparison always evaluates to false}}
5+
}
6+
7+
int add_idx_ptr_ult_ptr(const char *ptr, unsigned index) {
8+
return index + ptr < ptr; // expected-warning {{pointer comparison always evaluates to false}}
9+
}
10+
11+
int ptr_ugt_add_ptr_idx(const char *ptr, unsigned index) {
12+
return ptr > ptr + index; // expected-warning {{pointer comparison always evaluates to false}}
13+
}
14+
15+
int ptr_ugt_add_idx_ptr(const char *ptr, unsigned index) {
16+
return ptr > index + ptr; // expected-warning {{pointer comparison always evaluates to false}}
17+
}
18+
19+
int add_ptr_idx_uge_ptr(const char *ptr, unsigned index) {
20+
return ptr + index >= ptr; // expected-warning {{pointer comparison always evaluates to true}}
21+
}
22+
23+
int add_idx_ptr_uge_ptr(const char *ptr, unsigned index) {
24+
return index + ptr >= ptr; // expected-warning {{pointer comparison always evaluates to true}}
25+
}
26+
27+
int ptr_ule_add_ptr_idx(const char *ptr, unsigned index) {
28+
return ptr <= ptr + index; // expected-warning {{pointer comparison always evaluates to true}}
29+
}
30+
31+
int ptr_ule_add_idx_ptr(const char *ptr, unsigned index) {
32+
return ptr <= index + ptr; // expected-warning {{pointer comparison always evaluates to true}}
33+
}
34+
35+
int add_ptr_idx_ult_ptr_array(unsigned index) {
36+
char ptr[10];
37+
return ptr + index < ptr; // expected-warning {{pointer comparison always evaluates to false}}
38+
}
39+
40+
// Negative tests with wrong predicate.
41+
42+
int add_ptr_idx_ule_ptr(const char *ptr, unsigned index) {
43+
return ptr + index <= ptr;
44+
}
45+
46+
int add_ptr_idx_ugt_ptr(const char *ptr, unsigned index) {
47+
return ptr + index > ptr;
48+
}
49+
50+
int ptr_uge_add_idx_ptr(const char *ptr, unsigned index) {
51+
return ptr >= index + ptr;
52+
}
53+
54+
int ptr_ult_add_idx_ptr(const char *ptr, unsigned index) {
55+
return ptr < index + ptr;
56+
}
57+
58+
// Negative test with signed index.
59+
60+
int add_ptr_idx_ult_ptr_signed(const char *ptr, int index) {
61+
return ptr + index < ptr;
62+
}
63+
64+
// Negative test with unrelated pointers.
65+
66+
int add_ptr_idx_ult_ptr2(const char *ptr, const char *ptr2, unsigned index) {
67+
return ptr + index < ptr2;
68+
}
69+
70+
// Negative test with non-pointer operands.
71+
72+
int add_ptr_idx_ult_ptr_not_pointer(unsigned ptr, unsigned index) {
73+
return ptr + index < ptr;
74+
}

0 commit comments

Comments
 (0)