<div dir="ltr">Committed with a few tweaks as r190439.<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Sep 9, 2013 at 7:20 PM, Serge Pavlov <span dir="ltr"><<a href="mailto:sepavloff@gmail.com" target="_blank">sepavloff@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Friedly ping.</div><div class="gmail_extra"><div><div class="h5"><br><br><div class="gmail_quote">2013/8/30 Serge Pavlov <span dir="ltr"><<a href="mailto:sepavloff@gmail.com" target="_blank">sepavloff@gmail.com</a>></span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> Added giagnostics related to constexpr.<br>
Error is produced by the code that expects constexpr. However issuing a message why the<br>
expression is not constant is more user friendly. With this patch compiler generates an<br>
appropriate note, similar to other cases in expression evaluators. CCEDiag is used to<br>
report the message as this is core constant expression violation.<br>
<div><br>
Hi rsmith,<br>
<br>
<a href="http://llvm-reviews.chandlerc.com/D637" target="_blank">http://llvm-reviews.chandlerc.com/D637</a><br>
<br>
CHANGE SINCE LAST DIFF<br>
</div> <a href="http://llvm-reviews.chandlerc.com/D637?vs=3863&id=3913#toc" target="_blank">http://llvm-reviews.chandlerc.com/D637?vs=3863&id=3913#toc</a><br>
<br>
Files:<br>
include/clang/Basic/DiagnosticASTKinds.td<br>
<div> include/clang/Basic/DiagnosticSemaKinds.td<br>
lib/AST/ExprConstant.cpp<br>
lib/Sema/SemaExpr.cpp<br>
test/Sema/empty1.c<br>
test/SemaCXX/empty1.cpp<br>
<br>
</div><div>Index: include/clang/Basic/DiagnosticASTKinds.td<br>
===================================================================<br>
--- include/clang/Basic/DiagnosticASTKinds.td<br>
+++ include/clang/Basic/DiagnosticASTKinds.td<br>
</div>@@ -139,6 +139,8 @@<br>
def warn_integer_constant_overflow : Warning<<br>
"overflow in expression; result is %0 with type %1">,<br>
InGroup<DiagGroup<"integer-overflow">>;<br>
+def note_undefined_is_not_constexpr : Note<"operation with undefined behavior "<br>
+ "cannot be used in constant expression">;<br>
<br>
// inline asm related.<br>
let CategoryName = "Inline Assembly Issue" in {<br>
<div>Index: include/clang/Basic/DiagnosticSemaKinds.td<br>
===================================================================<br>
--- include/clang/Basic/DiagnosticSemaKinds.td<br>
+++ include/clang/Basic/DiagnosticSemaKinds.td<br>
</div>@@ -4179,6 +4179,9 @@<br>
<div> def warn_offsetof_non_standardlayout_type : ExtWarn<<br>
"offset of on non-standard-layout type %0">, InGroup<InvalidOffsetof>;<br>
def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;<br>
+def warn_sub_ptr_zero_size_types : Warning<<br>
+ "subtraction of pointers to type %0 of zero size has undefined behavior">,<br>
+ InGroup<PointerArith>;<br>
<br>
def warn_floatingpoint_eq : Warning<<br>
"comparing floating point with == or != is unsafe">,<br>
Index: lib/AST/ExprConstant.cpp<br>
===================================================================<br>
--- lib/AST/ExprConstant.cpp<br>
+++ lib/AST/ExprConstant.cpp<br>
</div>@@ -6570,6 +6570,17 @@<br>
<div> if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))<br>
return false;<br>
<br>
+ // As an extension, a type may have zero size (empty struct or union in<br>
+ // C, array of zero length). Meaning of pointer difference in such<br>
+ // case is unspecified.<br>
+ if (ElementSize.isZero()) {<br>
</div>+ // C++11 [expr.const]p2:<br>
+ // A conditional-expression is a core constant expression unless it<br>
+ // involves ... an operation that would have undefined behavior...<br>
+ CCEDiag(E, diag::note_undefined_is_not_constexpr);<br>
+ return false;<br>
+ }<br>
<div>+<br>
// FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime,<br>
// and produce incorrect results when it overflows. Such behavior<br>
// appears to be non-conforming, but is common, so perhaps we should<br>
</div><div>Index: lib/Sema/SemaExpr.cpp<br>
===================================================================<br>
--- lib/Sema/SemaExpr.cpp<br>
+++ lib/Sema/SemaExpr.cpp<br>
</div><div>@@ -7040,6 +7040,18 @@<br>
LHS.get(), RHS.get()))<br>
return QualType();<br>
<br>
+ // The pointee type may have zero size. As an extension, a structure or<br>
+ // union may have zero size or an array may have zero length. In this<br>
+ // case subtraction does not make sense.<br>
+ if (!rpointee->isVoidType() && !rpointee->isFunctionType()) {<br>
</div><div>+ CharUnits ElementSize = Context.getTypeSizeInChars(rpointee);<br>
</div><div>+ if (ElementSize.isZero()) {<br>
+ Diag(Loc,diag::warn_sub_ptr_zero_size_types)<br>
+ << rpointee.getUnqualifiedType()<br>
</div><div>+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();<br>
+ }<br>
</div><div>+ }<br>
+<br>
if (CompLHSTy) *CompLHSTy = LHS.get()->getType();<br>
return Context.getPointerDiffType();<br>
}<br>
Index: test/Sema/empty1.c<br>
===================================================================<br>
--- test/Sema/empty1.c<br>
+++ test/Sema/empty1.c<br>
@@ -36,3 +36,50 @@<br>
struct emp_1 f1;<br>
union emp_2 f2;<br>
};<br>
+<br>
+<br>
+// Checks for pointer subtraction (PR15683)<br>
+<br>
</div>+struct emp_1* func_1p (struct emp_1* x) {<br>
<div>+ return x - 5;<br>
+}<br>
+<br>
+int func_1 () {<br>
</div><div>+ struct emp_1 v[1];<br>
+ return v - v; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}<br>
</div>+}<br>
+<br>
+int func_2 (struct emp_1* x) {<br>
+ return 1 + x - x; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}<br>
+}<br>
+<br>
+int func_3 (struct emp_1* x, struct emp_1* y) {<br>
<div>+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}<br>
</div>+}<br>
+<br>
+int func_4 (struct emp_1* x, const struct emp_1* y) {<br>
<div>+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}<br>
</div>+}<br>
+<br>
<div><div>+int func_5 (volatile struct emp_1* x, const struct emp_1* y) {<br>
+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1' of zero size has undefined behavior}}<br>
+}<br>
+<br>
+int func_6 () {<br>
+ union emp_2 v[1];<br>
+ return v - v; // expected-warning {{subtraction of pointers to type 'union emp_2' of zero size has undefined behavior}}<br>
+}<br>
+<br>
+struct A; // expected-note {{forward declaration of 'struct A'}}<br>
+<br>
+int func_7 (struct A* x, struct A* y) {<br>
+ return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'struct A'}}<br>
+}<br>
+<br>
+int func_8 (struct emp_1 (*x)[10], struct emp_1 (*y)[10]) {<br>
+ return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1 [10]' of zero size has undefined behavior}}<br>
+}<br>
+<br>
+int func_9 (struct emp_1 (*x)[], struct emp_1 (*y)[]) {<br>
+ return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'struct emp_1 []'}}<br>
+}<br>
Index: test/SemaCXX/empty1.cpp<br>
===================================================================<br>
--- /dev/null<br>
+++ test/SemaCXX/empty1.cpp<br>
</div></div>@@ -0,0 +1,19 @@<br>
<div>+// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify<br>
+<br>
+int func_1(int (*p1)[0], int (*p2)[0]) {<br>
+ return p1 - p2; // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}}<br>
+}<br>
+<br>
+constexpr int (*p1)[0] = 0, (*p2)[0] = 0;<br>
+constexpr int k = p2 - p1; // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}} \<br>
</div>+ // expected-note {{operation with undefined behavior cannot be used in constant expression}} \<br>
<div><div>+ // expected-error {{constexpr variable 'k' must be initialized by a constant expression}}<br>
+<br>
+constexpr int func_2(int (*x1)[0], int (*x2)[0]) {<br>
+ return x1 - x2; // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}}<br>
+}<br>
+<br>
+constexpr int func_3(int (*x1)[0], long (*x2)[0]) {<br>
+ return x1 - x2; // expected-error {{int (*)[0]' and 'long (*)[0]' are not pointers to compatible types}} \<br>
+ // expected-warning {{of zero size has undefined behavior}}<br>
+}<br>
</div></div></blockquote></div><br><br clear="all"><div><br></div></div></div><span class="HOEnZb"><font color="#888888">-- <br>Thanks,<br>--Serge<br>
</font></span></div>
</blockquote></div><br></div>