From: Chris Lattner Date: Sun, 9 Dec 2007 21:53:25 +0000 (+0000) Subject: Implement correct semantic analysis of subtractions, implementing X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6e4ab61300e77f3cc303046c0107b8a961d7dc66;p=clang Implement correct semantic analysis of subtractions, implementing C99 6.5.6. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44746 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 8c5ef43f4c..3fa159eb44 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1259,14 +1259,60 @@ inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - // handle the common case first (both operands are arithmetic). + // Enforce type constraints: C99 6.5.6p3. + + // Handle the common case first (both operands are arithmetic). if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) return compType; + + // Either ptr - int or ptr - ptr. + if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { + // The LHS must be an object type, not incomplete, function, etc. + if (!LHSPTy->getPointeeType()->isObjectType()) { + // Handle the GNU void* extension. + if (LHSPTy->getPointeeType()->isVoidType()) { + Diag(loc, diag::ext_gnu_void_ptr, + lex->getSourceRange(), rex->getSourceRange()); + } else { + Diag(loc, diag::err_typecheck_sub_ptr_object, + lex->getType().getAsString(), lex->getSourceRange()); + return QualType(); + } + } + + // The result type of a pointer-int computation is the pointer type. + if (rex->getType()->isIntegerType()) + return lex->getType(); - if (lex->getType()->isPointerType() && rex->getType()->isIntegerType()) - return compType; - if (lex->getType()->isPointerType() && rex->getType()->isPointerType()) - return Context.getPointerDiffType(); + // Handle pointer-pointer subtractions. + if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) { + // RHS must be an object type, unless void (GNU). + if (!RHSPTy->getPointeeType()->isObjectType()) { + // Handle the GNU void* extension. + if (RHSPTy->getPointeeType()->isVoidType()) { + if (!LHSPTy->getPointeeType()->isVoidType()) + Diag(loc, diag::ext_gnu_void_ptr, + lex->getSourceRange(), rex->getSourceRange()); + } else { + Diag(loc, diag::err_typecheck_sub_ptr_object, + rex->getType().getAsString(), rex->getSourceRange()); + return QualType(); + } + } + + // Pointee types must be compatible. + if (!Context.typesAreCompatible(LHSPTy->getPointeeType(), + RHSPTy->getPointeeType())) { + Diag(loc, diag::err_typecheck_sub_ptr_compatible, + lex->getType().getAsString(), rex->getType().getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + return QualType(); + } + + return Context.getPointerDiffType(); + } + } + InvalidOperands(loc, lex, rex); return QualType(); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 043dcd4f34..e37262f93e 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -297,7 +297,9 @@ DIAG(ext_c99_compound_literal, EXTENSION, "compound literals are a C99-specific feature") DIAG(ext_c99_enumerator_list_comma, EXTENSION, "commas at the end of enumerator lists are a C99-specific feature") - + +DIAG(ext_gnu_void_ptr, EXTENSION, + "use of GNU void* extension") DIAG(ext_gnu_indirect_goto, EXTENSION, "use of GNU indirect-goto extension") DIAG(ext_gnu_address_of_label, EXTENSION, @@ -733,6 +735,10 @@ DIAG(ext_typecheck_deref_ptr_to_void, WARNING, "dereferencing '%0' pointer") DIAG(err_typecheck_invalid_operands, ERROR, "invalid operands to binary expression ('%0' and '%1')") +DIAG(err_typecheck_sub_ptr_object, ERROR, + "'%0' is not a complete object type") +DIAG(err_typecheck_sub_ptr_compatible, ERROR, + "'%0' and '%1' are not pointers to compatible types") DIAG(ext_typecheck_comparison_of_pointer_integer, WARNING, "comparison between pointer and integer ('%0' and '%1')") DIAG(ext_typecheck_comparison_of_distinct_pointers, WARNING, diff --git a/test/Sema/typecheck-binop.c b/test/Sema/typecheck-binop.c new file mode 100644 index 0000000000..05b9ad9067 --- /dev/null +++ b/test/Sema/typecheck-binop.c @@ -0,0 +1,20 @@ +/* RUN: clang %s -fsyntax-only -pedantic -verify + */ +struct incomplete; + +int sub1(int *a, double *b) { + return a - b; /* expected-error{{not pointers to compatible types}} */ +} + +void *sub2(struct incomplete *P) { + return P-4; /* expected-error{{not a complete object type}} */ +} + +void *sub3(void *P) { + return P-4; /* expected-warning{{GNU void* extension}} */ +} + +int sub4(void *P, void *Q) { + return P-Q; /* expected-warning{{GNU void* extension}} */ +} +