[PATCH] Fix to PR5683 - issue diagnostic for pointer subtraction with type of size zero.

Serge Pavlov sepavloff at gmail.com
Fri Aug 30 00:05:04 PDT 2013


  Added giagnostics related to constexpr.
  Error is produced by the code that expects constexpr. However issuing a message why the
  expression is not constant is more user friendly. With this patch compiler generates an
  appropriate note, similar to other cases in expression evaluators. CCEDiag is used to
  report the message as this is core constant expression violation.

Hi rsmith,

http://llvm-reviews.chandlerc.com/D637

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D637?vs=3863&id=3913#toc

Files:
  include/clang/Basic/DiagnosticASTKinds.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaExpr.cpp
  test/Sema/empty1.c
  test/SemaCXX/empty1.cpp

Index: include/clang/Basic/DiagnosticASTKinds.td
===================================================================
--- include/clang/Basic/DiagnosticASTKinds.td
+++ include/clang/Basic/DiagnosticASTKinds.td
@@ -139,6 +139,8 @@
 def warn_integer_constant_overflow : Warning<
   "overflow in expression; result is %0 with type %1">,
   InGroup<DiagGroup<"integer-overflow">>;
+def note_undefined_is_not_constexpr : Note<"operation with undefined behavior "
+  "cannot be used in constant expression">;
 
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4179,6 +4179,9 @@
 def warn_offsetof_non_standardlayout_type : ExtWarn<
   "offset of on non-standard-layout type %0">, InGroup<InvalidOffsetof>;
 def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
+def warn_sub_ptr_zero_size_types : Warning<
+  "subtraction of pointers to type %0 of zero size has undefined behavior">,
+  InGroup<PointerArith>;
 
 def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -6570,6 +6570,17 @@
         if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
           return false;
 
+        // As an extension, a type may have zero size (empty struct or union in
+        // C, array of zero length).  Meaning of pointer difference in such
+        // case is unspecified.
+        if (ElementSize.isZero()) {
+          // C++11 [expr.const]p2:
+          //   A conditional-expression is a core constant expression unless it
+          //   involves ... an operation that would have undefined behavior...
+          CCEDiag(E, diag::note_undefined_is_not_constexpr);
+          return false;
+        }
+
         // FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime,
         // and produce incorrect results when it overflows. Such behavior
         // appears to be non-conforming, but is common, so perhaps we should
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -7040,6 +7040,18 @@
                                                LHS.get(), RHS.get()))
         return QualType();
 
+      // The pointee type may have zero size.  As an extension, a structure or
+      // union may have zero size or an array may have zero length.  In this
+      // case subtraction does not make sense.
+      if (!rpointee->isVoidType() && !rpointee->isFunctionType()) {
+        CharUnits ElementSize = Context.getTypeSizeInChars(rpointee);
+        if (ElementSize.isZero()) {
+          Diag(Loc,diag::warn_sub_ptr_zero_size_types)
+            << rpointee.getUnqualifiedType()
+            << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+        }
+      }
+
       if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
       return Context.getPointerDiffType();
     }
Index: test/Sema/empty1.c
===================================================================
--- test/Sema/empty1.c
+++ test/Sema/empty1.c
@@ -36,3 +36,50 @@
   struct emp_1 f1;
   union emp_2 f2;
 };
+
+
+// Checks for pointer subtraction (PR15683)
+
+struct emp_1* func_1p (struct emp_1* x) {
+  return x - 5;
+}
+
+int func_1 () {
+  struct emp_1 v[1];
+  return v - v;  // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_2 (struct emp_1* x) {
+  return 1 + x - x;  // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_3 (struct emp_1* x, struct emp_1* y) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_4 (struct emp_1* x, const struct emp_1* y) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_5 (volatile struct emp_1* x, const struct emp_1* y) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}
+}
+
+int func_6 () {
+  union emp_2 v[1];
+  return v - v;  // expected-warning {{subtraction of pointers to type 'union emp_2' of zero size has undefined behavior}}
+}
+
+struct A;  // expected-note {{forward declaration of 'struct A'}}
+
+int func_7 (struct A* x, struct A* y) {
+  return x - y;  // expected-error {{arithmetic on a pointer to an incomplete type 'struct A'}}
+}
+
+int func_8 (struct emp_1 (*x)[10], struct emp_1 (*y)[10]) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct emp_1 [10]' of zero size has undefined behavior}}
+}
+
+int func_9 (struct emp_1 (*x)[], struct emp_1 (*y)[]) {
+  return x - y;  // expected-error {{arithmetic on a pointer to an incomplete type 'struct emp_1 []'}}
+}
Index: test/SemaCXX/empty1.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/empty1.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify
+
+int func_1(int (*p1)[0], int (*p2)[0]) {
+  return p1 - p2;  // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}}
+}
+
+constexpr int (*p1)[0] = 0, (*p2)[0] = 0;
+constexpr int k = p2 - p1;  // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}} \
+                            // expected-note {{operation with undefined behavior cannot be used in constant expression}} \
+                            // expected-error {{constexpr variable 'k' must be initialized by a constant expression}}
+
+constexpr int func_2(int (*x1)[0], int (*x2)[0]) {
+  return x1 - x2;  // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}}
+}
+
+constexpr int func_3(int (*x1)[0], long (*x2)[0]) {
+  return x1 - x2;  // expected-error {{int (*)[0]' and 'long (*)[0]' are not pointers to compatible types}} \
+                   // expected-warning {{of zero size has undefined behavior}}
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D637.11.patch
Type: text/x-patch
Size: 6449 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130830/7ae03469/attachment.bin>


More information about the cfe-commits mailing list