[Sema] Comparison of pointers to complete and incomplete types

Clang is missing one of the conditions for C99 6.5.9p2, where comparison
between pointers must either both point to incomplete types or both
point to complete types. This patch adds an extra check to the clause
where two pointers are of compatible types.

This only applies to C89/C99; the relevant part of the standard was
rewritten for C11.

Differential Revision: https://reviews.llvm.org/D79945
This commit is contained in:
Benson Chu
2020-06-19 17:01:03 -07:00
committed by Eli Friedman
parent ac716c0cc4
commit c310bf8256
3 changed files with 36 additions and 5 deletions
@@ -6446,6 +6446,12 @@ def err_typecheck_ordered_comparison_of_pointer_and_zero : Error<
"ordered comparison between pointer and zero (%0 and %1)">;
def err_typecheck_three_way_comparison_of_pointer_and_zero : Error<
"three-way comparison between pointer and zero">;
def ext_typecheck_compare_complete_incomplete_pointers : Extension<
"pointer comparisons before C11 "
"need to be between two complete or two incomplete types; "
"%0 is %select{|in}2complete and "
"%1 is %select{|in}3complete">,
InGroup<C11>;
def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn<
"ordered comparison of function pointers (%0 and %1)">,
InGroup<DiagGroup<"ordered-compare-function-pointers">>;
+16 -5
View File
@@ -11584,11 +11584,22 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C99 6.5.9p2 and C99 6.5.8p2
if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
RCanPointeeTy.getUnqualifiedType())) {
// Valid unless a relational comparison of function pointers
if (IsRelational && LCanPointeeTy->isFunctionType()) {
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
if (IsRelational) {
// Pointers both need to point to complete or incomplete types
if ((LCanPointeeTy->isIncompleteType() !=
RCanPointeeTy->isIncompleteType()) &&
!getLangOpts().C11) {
Diag(Loc, diag::ext_typecheck_compare_complete_incomplete_pointers)
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange()
<< LHSType << RHSType << LCanPointeeTy->isIncompleteType()
<< RCanPointeeTy->isIncompleteType();
}
if (LCanPointeeTy->isFunctionType()) {
// Valid unless a relational comparison of function pointers
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
}
}
} else if (!IsRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
@@ -0,0 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c99 -Wc11-extensions %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c89 -Wc11-extensions %s
int incomplete[]; // expected-warning {{tentative array definition assumed to have one element}}
int complete[6];
int test_comparison_between_incomplete_and_complete_pointer() {
return (&incomplete < &complete) && // expected-warning {{pointer comparisons before C11 need to be between two complete or two incomplete types; 'int (*)[]' is incomplete and 'int (*)[6]' is complete}}
(&incomplete <= &complete) && // expected-warning {{pointer comparisons before C11 need to be between two complete or two incomplete types; 'int (*)[]' is incomplete and 'int (*)[6]' is complete}}
(&incomplete > &complete) && // expected-warning {{pointer comparisons before C11 need to be between two complete or two incomplete types; 'int (*)[]' is incomplete and 'int (*)[6]' is complete}}
(&incomplete >= &complete) && // expected-warning {{pointer comparisons before C11 need to be between two complete or two incomplete types; 'int (*)[]' is incomplete and 'int (*)[6]' is complete}}
(&incomplete == &complete) &&
(&incomplete != &complete);
}