danielmarjamaki updated this revision to Diff 37582.
danielmarjamaki marked 5 inline comments as done.
danielmarjamaki added a comment.
One more work in progress patch.
I have moved the NonConstUse to VarDecl.
I turned on Wnonconst-parameter by default. This had a very positive effect; I
saw FPs in some tests that I had to fix.
I have moved the two MarkNonConstUse() together. The names are maybe not ideal
but having them together means it's easier to compare them now.
http://reviews.llvm.org/D12359
Files:
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Decl.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaOpenMP.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTReaderDecl.cpp
test/Analysis/NoReturn.m
test/Analysis/bstring.c
test/Analysis/casts.c
test/Analysis/coverage.c
test/Analysis/inlining/false-positive-suppression.c
test/Analysis/inlining/inline-defensive-checks.c
test/Analysis/inlining/path-notes.m
test/Analysis/logical-ops.c
test/Analysis/malloc.c
test/Analysis/misc-ps-region-store.m
test/Analysis/misc-ps.c
test/Analysis/misc-ps.m
test/Analysis/null-deref-ps.c
test/Analysis/objc-boxing.m
test/Analysis/pr22954.c
test/Analysis/ptr-arith.c
test/Analysis/retain-release-inline.m
test/Analysis/retain-release.m
test/Analysis/simple-stream-checks.c
test/Analysis/stack-addr-ps.c
test/Analysis/string.c
test/Analysis/svalbuilder-logic.c
test/Analysis/unix-fns.c
test/CodeGen/builtins-arm-exclusive.c
test/CodeGen/builtins-systemz.c
test/Parser/MicrosoftExtensionsInlineAsm.c
test/Parser/attributes.c
test/Parser/declarators.c
test/Parser/pointer-arithmetic.c
test/Sema/annotate.c
test/Sema/arm-neon-types.c
test/Sema/atomic-ops.c
test/Sema/builtin-assume-aligned.c
test/Sema/builtin-assume.c
test/Sema/builtins-arm-exclusive.c
test/Sema/builtins-arm64-exclusive.c
test/Sema/builtins.c
test/Sema/builtins.cl
test/Sema/c89.c
test/Sema/compare.c
test/Sema/crash-invalid-array.c
test/Sema/empty1.c
test/Sema/exprs.c
test/Sema/function.c
test/Sema/merge-decls.c
test/Sema/ms-inline-asm.c
test/Sema/pointer-subtract-compat.c
test/Sema/transparent-union.c
test/Sema/typecheck-binop.c
test/Sema/typo-correction.c
test/Sema/uninit-variables.c
test/Sema/unused-expr.c
test/Sema/varargs-x86-64.c
test/Sema/warn-logical-not-compare.c
test/Sema/warn-nonconst-parameter.c
test/Sema/warn-sizeof-arrayarg.c
test/Sema/warn-strncat-size.c
test/Sema/warn-thread-safety-analysis.c
test/Sema/warn-type-safety-mpi-hdf5.c
test/SemaObjC/nullability.m
test/SemaObjC/uninit-variables.m
test/SemaOpenCL/address-spaces.cl
test/SemaOpenCL/cond.cl
test/SemaOpenCL/event_t_overload.cl
Index: test/SemaOpenCL/event_t_overload.cl
===================================================================
--- test/SemaOpenCL/event_t_overload.cl
+++ test/SemaOpenCL/event_t_overload.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -Wno-nonconst-parameter -fsyntax-only
void __attribute__((overloadable)) foo(event_t, __local char *); // expected-note {{candidate function not viable: no known conversion from '__global int *' to '__local char *' for 2nd argument}}
void __attribute__((overloadable)) foo(event_t, __local float *); // expected-note {{candidate function not viable: no known conversion from '__global int *' to '__local float *' for 2nd argument}}
Index: test/SemaOpenCL/cond.cl
===================================================================
--- test/SemaOpenCL/cond.cl
+++ test/SemaOpenCL/cond.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -Wno-nonconst-parameter -fsyntax-only
typedef unsigned char uchar;
typedef unsigned char uchar2 __attribute__((ext_vector_type(2)));
Index: test/SemaOpenCL/address-spaces.cl
===================================================================
--- test/SemaOpenCL/address-spaces.cl
+++ test/SemaOpenCL/address-spaces.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -Wno-nonconst-parameter -fsyntax-only
__constant int ci = 1;
Index: test/SemaObjC/uninit-variables.m
===================================================================
--- test/SemaObjC/uninit-variables.m
+++ test/SemaObjC/uninit-variables.m
@@ -36,7 +36,7 @@
}
}
-int test_abort_on_exceptions(int y, NSException *e, NSString *s, int *z, ...) {
+int test_abort_on_exceptions(int y, NSException *e, NSString *s, const int *z, ...) {
int x; // expected-note {{initialize the variable 'x' to silence this warning}}
if (y == 1) {
va_list alist;
Index: test/SemaObjC/nullability.m
===================================================================
--- test/SemaObjC/nullability.m
+++ test/SemaObjC/nullability.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -Woverriding-method-mismatch -Wno-nullability-declspec %s -verify
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Woverriding-method-mismatch -Wno-nullability-declspec -Wno-nonconst-parameter %s -verify
__attribute__((objc_root_class))
@interface NSFoo
Index: test/Sema/warn-type-safety-mpi-hdf5.c
===================================================================
--- test/Sema/warn-type-safety-mpi-hdf5.c
+++ test/Sema/warn-type-safety-mpi-hdf5.c
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c99 -DMPICH -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -DOPEN_MPI -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -DMPICH -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fsyntax-only -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -std=c99 -DMPICH -fsyntax-only -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -DOPEN_MPI -fsyntax-only -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -DMPICH -fsyntax-only -Wno-nonconst-parameter -verify %s
//
-// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fno-signed-char -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c99 -DMPICH -fno-signed-char -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fno-signed-char -fsyntax-only -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -std=c99 -DMPICH -fno-signed-char -fsyntax-only -Wno-nonconst-parameter -verify %s
//===--- limits.h mock ----------------------------------------------------===//
Index: test/Sema/warn-thread-safety-analysis.c
===================================================================
--- test/Sema/warn-thread-safety-analysis.c
+++ test/Sema/warn-thread-safety-analysis.c
@@ -68,7 +68,7 @@
*a = value;
}
-int get_value(int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){
+int get_value(const int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){
return *p;
}
Index: test/Sema/warn-strncat-size.c
===================================================================
--- test/Sema/warn-strncat-size.c
+++ test/Sema/warn-strncat-size.c
@@ -24,7 +24,7 @@
char s2[200];
int x;
-void test(char *src) {
+void test(const char *src) {
char dest[10];
strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest) - 1); // no-warning
@@ -71,6 +71,6 @@
}
// Non-array type gets a different error message.
-void f(char* s, char* d) {
+void f(const char* s, char* d) {
strncat(d, s, sizeof(d)); // expected-warning {{the value of the size argument to 'strncat' is wrong}}
}
Index: test/Sema/warn-sizeof-arrayarg.c
===================================================================
--- test/Sema/warn-sizeof-arrayarg.c
+++ test/Sema/warn-sizeof-arrayarg.c
@@ -4,17 +4,17 @@
typedef int trungl_int;
-void f(int a[10], Arr arr) { // expected-note 4 {{declared here}}
+void f(const int a[10], const Arr arr) { // expected-note 4 {{declared here}}
/* Should warn. */
(void)sizeof(a); // \
- // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}}
+ // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const int [10]'}}
(void)sizeof((((a)))); // \
- // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}}
+ // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const int [10]'}}
(void)sizeof a; // \
- // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}}
+ // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const int [10]'}}
(void)sizeof arr; // \
- // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'Arr' (aka 'int [10]')}}
+ // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const Arr' (aka 'int const[10]')}}
/* Shouldn't warn. */
int b[10];
Index: test/Sema/warn-nonconst-parameter.c
===================================================================
--- test/Sema/warn-nonconst-parameter.c
+++ test/Sema/warn-nonconst-parameter.c
@@ -0,0 +1,159 @@
+// RUN: %clang_cc1 -fsyntax-only -Wnonconst-parameter -verify %s
+
+// Currently the -Wnonconst-parameter only warns about pointer arguments.
+//
+// It can be defined both that the data is const and that the pointer is const,
+// the -Wnonconst-parameter only checks if the data can be const-specified.
+//
+// It does not warn about pointers to records or function pointers.
+
+// Some external function where first argument is nonconst and second is const.
+char* strcpy1(char *dest, const char *src);
+unsigned my_strcpy(char *buf, const char *s);
+unsigned my_strlen(const char *buf);
+
+
+int warn1(int *p) { // expected-warning {{parameter 'p' can be const}}
+ return *p;
+}
+
+void warn2(int *first, int *last) { // expected-warning {{parameter 'last' can be const}}
+ *first = 0;
+ if (first < last) {} // <- last can be const
+}
+
+void warn3(char *p) { // expected-warning {{parameter 'p' can be const}}
+ char buf[10];
+ strcpy1(buf, p);
+}
+
+void assign1(int *p) {
+ *p = 0;
+}
+
+void assign2(char *p) {
+ p[0] = 0;
+}
+
+void assign3(int *p) {
+ int *q;
+ q = p++;
+}
+
+void assign4(char *p) {
+ char *a, *b;
+ a = b = p;
+}
+
+void assign5(char *p) {
+ char *x;
+ x = (p ? p : "");
+}
+
+void assign6(unsigned char *str, const unsigned int i) {
+ unsigned char *p;
+ for (p = str + i; *p; ) {}
+}
+
+void assign7(int *buf) {
+ int i, *p;
+ for (i=0, p=buf; i<10; i++, p++) {
+ *p = 1;
+ }
+}
+
+void assign8(int *p, int x) {
+ for (int *q = p+x-1; 0; q++);
+}
+
+
+void init1(int *p) {
+ int *q = p;
+ *q = 0;
+}
+
+void init2(float *p) {
+ int *q = (int *)p;
+}
+
+void init3(int *p) {
+ int *i = p ? p : 0;
+}
+
+void init4(int *p) {
+ int *a[] = {p,p,0};
+}
+
+
+int return1(const int *p) {
+ return *p;
+}
+
+char *return2(char *p) {
+ return p ? p : "";
+}
+
+char return3(int *p) {
+ return ++(*p);
+}
+
+char *return4(char *s) {
+ return s;
+}
+
+char *return5(char *s) {
+ return s+1;
+}
+
+
+void dontwarn1(int *p) {
+ ++(*p);
+}
+
+int dontwarn2(_Atomic(int) *p) {
+ return *p;
+}
+
+
+
+void callFunction1(char *p) {
+ strcpy1(p, "abc");
+}
+
+void callFunction2(char *p) {
+ strcpy1(&p[0], "abc");
+}
+
+void callFunction3(char *p) {
+ strcpy1(p+2, "abc");
+}
+
+char *callFunction4(char *p) {
+ return strcpy1(p, "abc");
+}
+
+unsigned callFunction5(char *buf) {
+ unsigned len = my_strlen(buf);
+ return len + my_strcpy(buf, "abc");
+}
+
+void f6(int **p);
+void callFunction6(int *p) { f6(&p); }
+
+typedef union {void*v;} t;
+void f7(t obj);
+void callFunction7(int *p) {
+ f7((t){p});
+}
+
+
+// Don't warn about nonconst function pointers that can be const.
+void functionpointer(double f(double), int x) {
+ f(x);
+}
+
+// Don't warn about nonconst record pointers that can be const.
+struct XY { int x; int y; };
+int recordpointer(struct XY *xy) {
+ return xy->x;
+}
Index: test/Sema/warn-logical-not-compare.c
===================================================================
--- test/Sema/warn-logical-not-compare.c
+++ test/Sema/warn-logical-not-compare.c
@@ -196,7 +196,7 @@
return ret;
}
-int compare_pointers(int* a, int* b) {
+int compare_pointers(const int* a, const int* b) {
int ret;
ret = !!a == !!b;
ret = !!a != !!b;
Index: test/Sema/varargs-x86-64.c
===================================================================
--- test/Sema/varargs-x86-64.c
+++ test/Sema/varargs-x86-64.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-apple-darwin9
+// RUN: %clang_cc1 -fsyntax-only -Wno-nonconst-parameter -verify %s -triple x86_64-apple-darwin9
// rdar://6726818
void f1() {
Index: test/Sema/unused-expr.c
===================================================================
--- test/Sema/unused-expr.c
+++ test/Sema/unused-expr.c
@@ -4,7 +4,7 @@
double sqrt(double X); // implicitly const because of no -fmath-errno!
-void bar(volatile int *VP, int *P, int A,
+void bar(volatile const int *VP, const int *P, int A,
_Complex double C, volatile _Complex double VC) {
VP < P; // expected-warning {{relational comparison result unused}}
Index: test/Sema/uninit-variables.c
===================================================================
--- test/Sema/uninit-variables.c
+++ test/Sema/uninit-variables.c
@@ -486,7 +486,7 @@
return a;
}
-int compound_assign(int *arr, int n) {
+int compound_assign(const int *arr, int n) {
int sum; // expected-note {{initialize}}
for (int i = 0; i < n; ++i)
sum += arr[i]; // expected-warning {{variable 'sum' is uninitialized}}
@@ -504,7 +504,7 @@
return x;
}
-int self_init_in_cond(int *p) {
+int self_init_in_cond(const int *p) {
int n = ((p && (0 || 1)) && (n = *p)) ? n : -1; // ok
return n;
}
Index: test/Sema/typo-correction.c
===================================================================
--- test/Sema/typo-correction.c
+++ test/Sema/typo-correction.c
@@ -41,7 +41,7 @@
// expected-error {{use of undeclared identifier '__v2di'}}
}
-void f(long *a, long b) {
+void f(const long *a, long b) {
__atomic_or_fetch(a, b, c); // expected-error {{use of undeclared identifier 'c'}}
}
Index: test/Sema/typecheck-binop.c
===================================================================
--- test/Sema/typecheck-binop.c
+++ test/Sema/typecheck-binop.c
@@ -2,7 +2,7 @@
*/
struct incomplete; // expected-note{{forward declaration of 'struct incomplete'}}
-int sub1(int *a, double *b) {
+int sub1(const int *a, const double *b) {
return a - b; /* expected-error{{not pointers to compatible types}} */
}
@@ -18,7 +18,7 @@
return P-Q; /* expected-warning{{arithmetic on pointers to void is a GNU extension}} */
}
-int sub5(void *P, int *Q) {
+int sub5(void *P, const int *Q) {
return P-Q; /* expected-error{{not pointers to compatible types}} */
}
Index: test/Sema/transparent-union.c
===================================================================
--- test/Sema/transparent-union.c
+++ test/Sema/transparent-union.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-nonconst-parameter -verify %s
typedef union {
int *ip;
float *fp;
Index: test/Sema/pointer-subtract-compat.c
===================================================================
--- test/Sema/pointer-subtract-compat.c
+++ test/Sema/pointer-subtract-compat.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
typedef const char rchar;
-int a(char* a, rchar* b) {
+int a(const char* a, rchar* b) {
return a-b;
}
Index: test/Sema/ms-inline-asm.c
===================================================================
--- test/Sema/ms-inline-asm.c
+++ test/Sema/ms-inline-asm.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fms-extensions -fasm-blocks -Wno-microsoft -Wunused-label -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fms-extensions -fasm-blocks -Wno-microsoft -Wunused-label -Wno-nonconst-parameter -verify -fsyntax-only
void t1(void) {
__asm __asm // expected-error {{__asm used with no assembly instructions}}
Index: test/Sema/merge-decls.c
===================================================================
--- test/Sema/merge-decls.c
+++ test/Sema/merge-decls.c
@@ -71,9 +71,9 @@
int v[sizeof(a) == 1 ? 1 : -1];
}
-int test5_f(int (*)[10]);
-int test5_f(int (*x)[]) {
- return sizeof(*x); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+int test5_f(const int (*)[10]);
+int test5_f(const int (*x)[]) {
+ return sizeof(*x); // expected-error {{invalid application of 'sizeof' to an incomplete type 'const int []'}}
}
void test6_f(int (*a)[11]);
Index: test/Sema/function.c
===================================================================
--- test/Sema/function.c
+++ test/Sema/function.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
// PR1892, PR11354
-void f(double a[restrict][5]) { __typeof(a) x = 10; } // expected-warning {{(aka 'double (*restrict)[5]')}}
+void f(const double a[restrict][5]) { __typeof(a) x = 10; } // expected-warning {{(aka 'const double (*restrict)[5]')}}
int foo (__const char *__path);
int foo(__const char *__restrict __file);
Index: test/Sema/exprs.c
===================================================================
--- test/Sema/exprs.c
+++ test/Sema/exprs.c
@@ -66,7 +66,7 @@
}
// rdar://6319320
-void test5(int *X, float *P) {
+void test5(const int *X, const float *P) {
(float*)X = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
#define FOO ((float*) X)
FOO = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
@@ -77,8 +77,8 @@
X(); // expected-error {{called object type 'int' is not a function or function pointer}}
}
-void test7(int *P, _Complex float Gamma) {
- P = (P-42) + Gamma*4; // expected-error {{invalid operands to binary expression ('int *' and '_Complex float')}}
+void test7(const int *P, _Complex float Gamma) {
+ P = (P-42) + Gamma*4; // expected-error {{invalid operands to binary expression ('const int *' and '_Complex float')}}
}
Index: test/Sema/empty1.c
===================================================================
--- test/Sema/empty1.c
+++ test/Sema/empty1.c
@@ -74,14 +74,14 @@
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_8(const struct emp_1 (*x)[10], const struct emp_1 (*y)[10]) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'const 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 []'}}
+int func_9(const struct emp_1 (*x)[], const struct emp_1 (*y)[]) {
+ return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'const struct emp_1 []'}}
}
-int func_10(int (*x)[0], int (*y)[0]) {
- return x - y; // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}}
+int func_10(const int (*x)[0], const int (*y)[0]) {
+ return x - y; // expected-warning {{subtraction of pointers to type 'const int [0]' of zero size has undefined behavior}}
}
Index: test/Sema/crash-invalid-array.c
===================================================================
--- test/Sema/crash-invalid-array.c
+++ test/Sema/crash-invalid-array.c
@@ -15,8 +15,8 @@
}
// rdar://13705391
-void foo(int a[*][2]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}}
-void foo1(int a[2][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}}
-void foo2(int a[*][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}}
-void foo3(int a[2][*][2]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}}
-void foo4(int a[2][*][*]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}}
+void foo(const int a[*][2]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}}
+void foo1(const int a[2][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}}
+void foo2(const int a[*][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}}
+void foo3(const int a[2][*][2]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}}
+void foo4(const int a[2][*][*]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}}
Index: test/Sema/compare.c
===================================================================
--- test/Sema/compare.c
+++ test/Sema/compare.c
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare %s -Wno-unreachable-code
-int test(char *C) { // nothing here should warn.
+int test(const char *C) { // nothing here should warn.
return C != ((void*)0);
return C != (void*)0;
return C != 0;
- return C != 1; // expected-warning {{comparison between pointer and integer ('char *' and 'int')}}
+ return C != 1; // expected-warning {{comparison between pointer and integer ('const char *' and 'int')}}
}
int ints(long a, unsigned long b) {
@@ -201,18 +201,18 @@
;
}
-int equal(char *a, const char *b) {
+int equal(const char *a, const char *b) {
return a == b;
}
-int arrays(char (*a)[5], char(*b)[10], char(*c)[5]) {
+int arrays(const char (*a)[5], const char(*b)[10], const char(*c)[5]) {
int d = (a == c);
return a == b; // expected-warning {{comparison of distinct pointer types}}
}
-int pointers(int *a) {
- return a > 0; // expected-warning {{ordered comparison between pointer and zero ('int *' and 'int') is an extension}}
- return a > 42; // expected-warning {{ordered comparison between pointer and integer ('int *' and 'int')}}
+int pointers(const int *a) {
+ return a > 0; // expected-warning {{ordered comparison between pointer and zero ('const int *' and 'int') is an extension}}
+ return a > 42; // expected-warning {{ordered comparison between pointer and integer ('const int *' and 'int')}}
return a > (void *)0; // expected-warning {{comparison of distinct pointer types}}
}
Index: test/Sema/c89.c
===================================================================
--- test/Sema/c89.c
+++ test/Sema/c89.c
@@ -64,7 +64,7 @@
void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature}} */
void test11 (int x[static 4]); /* expected-warning {{static array size is a C99 feature}} */
-void test12 (int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */
+void test12 (const int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */
int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} */
}
Index: test/Sema/builtins.cl
===================================================================
--- test/Sema/builtins.cl
+++ test/Sema/builtins.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-nonconst-parameter -verify -pedantic
// expected-no-diagnostics
kernel void test(global float *out, global float *in, global int* in2) {
Index: test/Sema/builtins.c
===================================================================
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wstrlcpy-strlcat-size -Wno-string-plus-int -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wstrlcpy-strlcat-size -Wno-string-plus-int -Wno-nonconst-parameter -triple=i686-apple-darwin9
// This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
int test1(float a, int b) {
Index: test/Sema/builtins-arm64-exclusive.c
===================================================================
--- test/Sema/builtins-arm64-exclusive.c
+++ test/Sema/builtins-arm64-exclusive.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -fsyntax-only -Wno-nonconst-parameter -verify %s
struct Simple {
char a, b;
Index: test/Sema/builtins-arm-exclusive.c
===================================================================
--- test/Sema/builtins-arm-exclusive.c
+++ test/Sema/builtins-arm-exclusive.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple armv7 -fsyntax-only -Wno-nonconst-parameter -verify %s
struct Simple {
char a, b;
Index: test/Sema/builtin-assume.c
===================================================================
--- test/Sema/builtin-assume.c
+++ test/Sema/builtin-assume.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -fsyntax-only -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wno-nonconst-parameter -verify %s
int nonconst(void);
int isconst(void) __attribute__((const));
Index: test/Sema/builtin-assume-aligned.c
===================================================================
--- test/Sema/builtin-assume-aligned.c
+++ test/Sema/builtin-assume-aligned.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-nonconst-parameter -verify %s
int test1(int *a) {
a = __builtin_assume_aligned(a, 32, 0ull);
Index: test/Sema/atomic-ops.c
===================================================================
--- test/Sema/atomic-ops.c
+++ test/Sema/atomic-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -triple=i686-linux-gnu -std=c11
+// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -Wno-nonconst-parameter -triple=i686-linux-gnu -std=c11
// Basic parsing/Sema tests for __c11_atomic_*
Index: test/Sema/arm-neon-types.c
===================================================================
--- test/Sema/arm-neon-types.c
+++ test/Sema/arm-neon-types.c
@@ -28,7 +28,7 @@
}
// Warn for incompatible pointer types used with vld/vst intrinsics.
-int16x8_t test5(int *p) {
+int16x8_t test5(const int *p) {
return vld1q_s16(p); // expected-warning {{incompatible pointer types}}
}
void test6(float *p, int32x2_t v) {
Index: test/Sema/annotate.c
===================================================================
--- test/Sema/annotate.c
+++ test/Sema/annotate.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
-void __attribute__((annotate("foo"))) foo(float *a) {
+void __attribute__((annotate("foo"))) foo(const float *a) {
__attribute__((annotate("bar"))) int x;
__attribute__((annotate(1))) int y; // expected-error {{'annotate' attribute requires a string}}
__attribute__((annotate("bar", 1))) int z; // expected-error {{'annotate' attribute takes one argument}}
Index: test/Parser/pointer-arithmetic.c
===================================================================
--- test/Parser/pointer-arithmetic.c
+++ test/Parser/pointer-arithmetic.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int *test1(int *a) { return a + 1; }
-int *test2(int *a) { return 1 + a; }
-int *test3(int *a) { return a - 1; }
-int test4(int *a, int *b) { return a - b; }
+int *test1(int *a) { return a + 1; }
+int *test2(int *a) { return 1 + a; }
+int *test3(int *a) { return a - 1; }
+int test4(const int *a, const int *b) { return a - b; }
-int test5(int *a, int *b) { return a + b; } /* expected-error {{invalid operands}} */
-int *test6(int *a) { return 1 - a; } /* expected-error {{invalid operands}} */
+int test5(const int *a, const int *b) { return a + b; } /* expected-error {{invalid operands}} */
+int *test6(const int *a) { return 1 - a; } /* expected-error {{invalid operands}} */
Index: test/Parser/declarators.c
===================================================================
--- test/Parser/declarators.c
+++ test/Parser/declarators.c
@@ -19,7 +19,7 @@
struct str;
-void test2(int *P, int A) {
+void test2(const int *P, int A) {
struct str;
// Hard case for array decl, not Array[*].
Index: test/Parser/attributes.c
===================================================================
--- test/Parser/attributes.c
+++ test/Parser/attributes.c
@@ -64,7 +64,7 @@
-int testFundef1(int *a) __attribute__((nonnull(1))) { // \
+int testFundef1(const int *a) __attribute__((nonnull(1))) { // \
// expected-warning {{GCC does not allow 'nonnull' attribute in this position on a function definition}}
return *a;
}
@@ -75,14 +75,14 @@
testFundef2();
}
-int testFundef3(int *a) __attribute__((nonnull(1), // \
+int testFundef3(const int *a) __attribute__((nonnull(1), // \
// expected-warning {{GCC does not allow 'nonnull' attribute in this position on a function definition}}
pure)) { // \
// expected-warning {{GCC does not allow 'pure' attribute in this position on a function definition}}
return *a;
}
-int testFundef4(int *a) __attribute__((nonnull(1))) // \
+int testFundef4(const int *a) __attribute__((nonnull(1))) // \
// expected-warning {{GCC does not allow 'nonnull' attribute in this position on a function definition}}
__attribute((pure)) { // \
// expected-warning {{GCC does not allow 'pure' attribute in this position on a function definition}}
Index: test/Parser/MicrosoftExtensionsInlineAsm.c
===================================================================
--- test/Parser/MicrosoftExtensionsInlineAsm.c
+++ test/Parser/MicrosoftExtensionsInlineAsm.c
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -verify -fms-extensions %s
// expected-no-diagnostics
-void __forceinline InterlockedBitTestAndSet (long *Base, long Bit)
+void __forceinline InterlockedBitTestAndSet (const long *Base, long Bit)
{
__asm {
mov eax, Bit
Index: test/CodeGen/builtins-systemz.c
===================================================================
--- test/CodeGen/builtins-systemz.c
+++ test/CodeGen/builtins-systemz.c
@@ -9,7 +9,7 @@
uint64_t g;
struct __htm_tdb global_tdb;
-void test_htm1(struct __htm_tdb *tdb, int reg, int *mem, uint64_t *mem64) {
+void test_htm1(struct __htm_tdb *tdb, int reg, const int *mem, uint64_t *mem64) {
// CHECK-LABEL: test_htm1
__builtin_tbegin ((void *)0);
Index: test/CodeGen/builtins-arm-exclusive.c
===================================================================
--- test/CodeGen/builtins-arm-exclusive.c
+++ test/CodeGen/builtins-arm-exclusive.c
@@ -1,6 +1,6 @@
// REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -O3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-ARM64
+// RUN: %clang_cc1 -Wall -Wno-nonconst-parameter -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Wall -Wno-nonconst-parameter -Werror -triple arm64-apple-ios7.0 -O3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-ARM64
// Make sure the canonical use works before going into smaller details:
int atomic_inc(int *addr) {
@@ -32,7 +32,7 @@
char a, b;
};
-int test_ldrex(char *addr, long long *addr64, float *addrfloat) {
+int test_ldrex(const char *addr, const long long *addr64, const float *addrfloat) {
// CHECK-LABEL: @test_ldrex
// CHECK-ARM64-LABEL: @test_ldrex
int sum = 0;
@@ -116,7 +116,7 @@
return sum;
}
-int test_ldaex(char *addr, long long *addr64, float *addrfloat) {
+int test_ldaex(const char *addr, const long long *addr64, const float *addrfloat) {
// CHECK-LABEL: @test_ldaex
// CHECK-ARM64-LABEL: @test_ldaex
int sum = 0;
Index: test/Analysis/unix-fns.c
===================================================================
--- test/Analysis/unix-fns.c
+++ test/Analysis/unix-fns.c
@@ -185,7 +185,7 @@
}
// Test inlining of dispatch_sync.
-void test_dispatch_sync(dispatch_queue_t queue, int *q) {
+void test_dispatch_sync(dispatch_queue_t queue, const int *q) {
int *p = 0;
dispatch_sync(queue, ^(void){
if (q) {
Index: test/Analysis/svalbuilder-logic.c
===================================================================
--- test/Analysis/svalbuilder-logic.c
+++ test/Analysis/svalbuilder-logic.c
@@ -3,7 +3,7 @@
// Testing core functionality of the SValBuilder.
-int SValBuilderLogicNoCrash(int *x) {
+int SValBuilderLogicNoCrash(const int *x) {
return 3 - (int)(x +3);
}
Index: test/Analysis/string.c
===================================================================
--- test/Analysis/string.c
+++ test/Analysis/string.c
@@ -221,11 +221,11 @@
return strnlen("abc", (int)f);
}
-void strnlen_is_not_strlen(char *x) {
+void strnlen_is_not_strlen(const char *x) {
clang_analyzer_eval(strnlen(x, 10) == strlen(x)); // expected-warning{{UNKNOWN}}
}
-void strnlen_at_limit(char *x) {
+void strnlen_at_limit(const char *x) {
size_t len = strnlen(x, 10);
clang_analyzer_eval(len <= 10); // expected-warning{{TRUE}}
clang_analyzer_eval(len == 10); // expected-warning{{UNKNOWN}}
@@ -263,7 +263,7 @@
#endif /* VARIANT */
-void strcpy_null_dst(char *x) {
+void strcpy_null_dst(const char *x) {
strcpy(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}}
}
@@ -280,7 +280,7 @@
}
extern int globalInt;
-void strcpy_effects(char *x, char *y) {
+void strcpy_effects(char *x, const char *y) {
char a = x[0];
if (globalInt != 42)
return;
@@ -291,13 +291,13 @@
clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
}
-void strcpy_overflow(char *y) {
+void strcpy_overflow(const char *y) {
char x[4];
if (strlen(y) == 4)
strcpy(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
-void strcpy_no_overflow(char *y) {
+void strcpy_no_overflow(const char *y) {
char x[4];
if (strlen(y) == 3)
strcpy(x, y); // no-warning
@@ -322,21 +322,21 @@
#endif /* VARIANT */
-void stpcpy_effect(char *x, char *y) {
+void stpcpy_effect(char *x, const char *y) {
char a = x[0];
clang_analyzer_eval(stpcpy(x, y) == &x[strlen(y)]); // expected-warning{{TRUE}}
clang_analyzer_eval(strlen(x) == strlen(y)); // expected-warning{{TRUE}}
clang_analyzer_eval(a == x[0]); // expected-warning{{UNKNOWN}}
}
-void stpcpy_overflow(char *y) {
+void stpcpy_overflow(const char *y) {
char x[4];
if (strlen(y) == 4)
stpcpy(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
-void stpcpy_no_overflow(char *y) {
+void stpcpy_no_overflow(const char *y) {
char x[4];
if (strlen(y) == 3)
stpcpy(x, y); // no-warning
@@ -361,7 +361,7 @@
#endif /* VARIANT */
-void strcat_null_dst(char *x) {
+void strcat_null_dst(const char *x) {
strcat(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}}
}
@@ -373,7 +373,7 @@
strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcat_fn', which is not a null-terminated string}}
}
-void strcat_effects(char *y) {
+void strcat_effects(const char *y) {
char x[8] = "123";
size_t orig_len = strlen(x);
char a = x[0];
@@ -385,25 +385,25 @@
clang_analyzer_eval((int)strlen(x) == (orig_len + strlen(y))); // expected-warning{{TRUE}}
}
-void strcat_overflow_0(char *y) {
+void strcat_overflow_0(const char *y) {
char x[4] = "12";
if (strlen(y) == 4)
strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
-void strcat_overflow_1(char *y) {
+void strcat_overflow_1(const char *y) {
char x[4] = "12";
if (strlen(y) == 3)
strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
-void strcat_overflow_2(char *y) {
+void strcat_overflow_2(const char *y) {
char x[4] = "12";
if (strlen(y) == 2)
strcat(x, y); // expected-warning{{String copy function overflows destination buffer}}
}
-void strcat_no_overflow(char *y) {
+void strcat_no_overflow(const char *y) {
char x[5] = "12";
if (strlen(y) == 2)
strcat(x, y); // no-warning
@@ -429,7 +429,7 @@
// There is no strcat_unknown_dst_length because if we can't get a symbolic
// length for the "before" strlen, we won't be able to set one for "after".
-void strcat_too_big(char *dst, char *src) {
+void strcat_too_big(char *dst, const char *src) {
// We assume this can never actually happen, so we don't get a warning.
if (strlen(dst) != (((size_t)0) - 2))
return;
@@ -458,7 +458,7 @@
#endif /* VARIANT */
-void strncpy_null_dst(char *x) {
+void strncpy_null_dst(const char *x) {
strncpy(NULL, x, 5); // expected-warning{{Null pointer argument in call to string copy function}}
}
@@ -470,57 +470,57 @@
strncpy(x, (char*)&strcpy_fn, 5); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}
-void strncpy_effects(char *x, char *y) {
+void strncpy_effects(char *x, const char *y) {
char a = x[0];
clang_analyzer_eval(strncpy(x, y, 5) == x); // expected-warning{{TRUE}}
clang_analyzer_eval(strlen(x) == strlen(y)); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(a == x[0]); // expected-warning{{UNKNOWN}}
}
-void strncpy_overflow(char *y) {
+void strncpy_overflow(const char *y) {
char x[4];
if (strlen(y) == 4)
strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}}
}
-void strncpy_no_overflow(char *y) {
+void strncpy_no_overflow(const char *y) {
char x[4];
if (strlen(y) == 3)
strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}}
}
-void strncpy_no_overflow2(char *y, int n) {
+void strncpy_no_overflow2(const char *y, int n) {
if (n <= 4)
return;
char x[4];
if (strlen(y) == 3)
strncpy(x, y, n); // expected-warning{{Size argument is greater than the length of the destination buffer}}
}
-void strncpy_truncate(char *y) {
+void strncpy_truncate(const char *y) {
char x[4];
if (strlen(y) == 4)
strncpy(x, y, 3); // no-warning
}
-void strncpy_no_truncate(char *y) {
+void strncpy_no_truncate(const char *y) {
char x[4];
if (strlen(y) == 3)
strncpy(x, y, 3); // no-warning
}
-void strncpy_exactly_matching_buffer(char *y) {
+void strncpy_exactly_matching_buffer(const char *y) {
char x[4];
strncpy(x, y, 4); // no-warning
// strncpy does not null-terminate, so we have no idea what the strlen is
// after this.
clang_analyzer_eval(strlen(x) > 4); // expected-warning{{UNKNOWN}}
}
-void strncpy_zero(char *src) {
+void strncpy_zero(const char *src) {
char dst[] = "123";
strncpy(dst, src, 0); // no-warning
}
@@ -550,7 +550,7 @@
#endif /* VARIANT */
-void strncat_null_dst(char *x) {
+void strncat_null_dst(const char *x) {
strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to string copy function}}
}
@@ -562,7 +562,7 @@
strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to string copy function is the address of the function 'strncat_fn', which is not a null-terminated string}}
}
-void strncat_effects(char *y) {
+void strncat_effects(const char *y) {
char x[8] = "123";
size_t orig_len = strlen(x);
char a = x[0];
@@ -574,36 +574,36 @@
clang_analyzer_eval(strlen(x) == (orig_len + strlen(y))); // expected-warning{{TRUE}}
}
-void strncat_overflow_0(char *y) {
+void strncat_overflow_0(const char *y) {
char x[4] = "12";
if (strlen(y) == 4)
strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
-void strncat_overflow_1(char *y) {
+void strncat_overflow_1(const char *y) {
char x[4] = "12";
if (strlen(y) == 3)
strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
-void strncat_overflow_2(char *y) {
+void strncat_overflow_2(const char *y) {
char x[4] = "12";
if (strlen(y) == 2)
strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
-void strncat_overflow_3(char *y) {
+void strncat_overflow_3(const char *y) {
char x[4] = "12";
if (strlen(y) == 4)
strncat(x, y, 2); // expected-warning{{Size argument is greater than the free space in the destination buffer}}
}
-void strncat_no_overflow_1(char *y) {
+void strncat_no_overflow_1(const char *y) {
char x[5] = "12";
if (strlen(y) == 2)
strncat(x, y, strlen(y)); // no-warning
}
-void strncat_no_overflow_2(char *y) {
+void strncat_no_overflow_2(const char *y) {
char x[4] = "12";
if (strlen(y) == 4)
strncat(x, y, 1); // no-warning
@@ -614,7 +614,7 @@
clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{TRUE}}
}
-void strncat_symbolic_src_length(char *src) {
+void strncat_symbolic_src_length(const char *src) {
char dst[8] = "1234";
strncat(dst, src, 3);
clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{TRUE}}
@@ -653,16 +653,16 @@
clang_analyzer_eval(strlen(dst) == 4); // expected-warning{{UNKNOWN}}
}
-void strncat_too_big(char *dst, char *src) {
+void strncat_too_big(char *dst, const char *src) {
// We assume this will never actually happen, so we don't get a warning.
if (strlen(dst) != (((size_t)0) - 2))
return;
if (strlen(src) != 2)
return;
strncat(dst, src, 2);
}
-void strncat_zero(char *src) {
+void strncat_zero(const char *src) {
char dst[] = "123";
strncat(dst, src, 0); // no-warning
}
@@ -752,7 +752,7 @@
clang_analyzer_eval(strcmp("\0z", "\0y") == 0); // expected-warning{{TRUE}}
}
-void strcmp_unknown_arg (char *unknown) {
+void strcmp_unknown_arg (const char *unknown) {
clang_analyzer_eval(strcmp(unknown, unknown) == 0); // expected-warning{{TRUE}}
}
@@ -1088,15 +1088,15 @@
// aggressive in marking the (length of) src symbol dead. The length of dst
// depends on src. This could be explicitely specified in the checker or the
// logic for handling MetadataSymbol in SymbolManager needs to change.
-void strcat_symbolic_src_length(char *src) {
+void strcat_symbolic_src_length(const char *src) {
char dst[8] = "1234";
strcat(dst, src);
clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{UNKNOWN}}
}
// The analyzer_eval call below should evaluate to true. Most likely the same
// issue as the test above.
-void strncpy_exactly_matching_buffer2(char *y) {
+void strncpy_exactly_matching_buffer2(const char *y) {
if (strlen(y) >= 4)
return;
Index: test/Analysis/stack-addr-ps.c
===================================================================
--- test/Analysis/stack-addr-ps.c
+++ test/Analysis/stack-addr-ps.c
@@ -38,7 +38,7 @@
return p; // expected-warning{{Address of stack memory}}
}
-int array_test(int x[2]) {
+int array_test(const int x[2]) {
return x[0]; // no-warning
}
Index: test/Analysis/simple-stream-checks.c
===================================================================
--- test/Analysis/simple-stream-checks.c
+++ test/Analysis/simple-stream-checks.c
@@ -2,7 +2,7 @@
#include "Inputs/system-header-simulator-for-simple-stream.h"
-void checkDoubleFClose(int *Data) {
+void checkDoubleFClose(const int *Data) {
FILE *F = fopen("myfile.txt", "w");
if (F != 0) {
fputs ("fopen example", F);
@@ -14,7 +14,7 @@
}
}
-int checkLeak(int *Data) {
+int checkLeak(const int *Data) {
FILE *F = fopen("myfile.txt", "w");
if (F != 0) {
fputs ("fopen example", F);
@@ -26,7 +26,7 @@
return 0;
}
-void checkLeakFollowedByAssert(int *Data) {
+void checkLeakFollowedByAssert(const int *Data) {
FILE *F = fopen("myfile.txt", "w");
if (F != 0) {
fputs ("fopen example", F);
@@ -71,7 +71,7 @@
return; // no warning
}
-void SymbolDoesNotEscapeThoughStringAPIs(char *Data) {
+void SymbolDoesNotEscapeThoughStringAPIs(const char *Data) {
FILE *F = fopen("myfile.txt", "w");
fputc(*Data, F);
return; // expected-warning {{Opened file is never closed; potential resource leak}}
Index: test/Analysis/retain-release.m
===================================================================
--- test/Analysis/retain-release.m
+++ test/Analysis/retain-release.m
@@ -605,7 +605,7 @@
// <rdar://problem/6659160>
int isFoo(char c);
-static void rdar_6659160(char *inkind, char *inname)
+static void rdar_6659160(const char *inkind, const char *inname)
{
// We currently expect that [NSObject alloc] cannot fail. This
// will be a toggled flag in the future. It can indeed return null, but
Index: test/Analysis/retain-release-inline.m
===================================================================
--- test/Analysis/retain-release-inline.m
+++ test/Analysis/retain-release-inline.m
@@ -299,7 +299,7 @@
//===----------------------------------------------------------------------===//
// On return (intraprocedural), assume CF objects are leaked.
-CFStringRef test_return_ratained_CF(char *bytes) {
+CFStringRef test_return_ratained_CF(const char *bytes) {
CFStringRef str;
return CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}}
}
@@ -325,7 +325,7 @@
return x;
}
-void test_test_return_inline(char *bytes) {
+void test_test_return_inline(const char *bytes) {
CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0);
// After this call, 'str' really has +2 reference count.
CFStringRef str2 = test_return_inline(str);
@@ -335,7 +335,7 @@
CFRelease(str2);
}
-void test_test_return_inline_2(char *bytes) {
+void test_test_return_inline_2(const char *bytes) {
CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}}
// After this call, 'str' really has +2 reference count.
CFStringRef str2 = test_return_inline(str);
Index: test/Analysis/ptr-arith.c
===================================================================
--- test/Analysis/ptr-arith.c
+++ test/Analysis/ptr-arith.c
@@ -63,7 +63,7 @@
int d = q - p; // no-warning
}
-void null_operand(int *a) {
+void null_operand(const int *a) {
start:
// LHS is a label, RHS is NULL
clang_analyzer_eval(&&start != 0); // expected-warning{{TRUE}}
@@ -155,20 +155,20 @@
clang_analyzer_eval(&a >= &b); // expected-warning{{UNKNOWN}}
}
-void symbolic_region(int *p) {
+void symbolic_region(const int *p) {
int a;
clang_analyzer_eval(&a != p); // expected-warning{{TRUE}}
clang_analyzer_eval(&a > p); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(&a >= p); // expected-warning{{UNKNOWN}}
}
-void PR7527 (int *p) {
+void PR7527 (const int *p) {
if (((int) p) & 1) // not crash
return;
}
-void use_symbols(int *lhs, int *rhs) {
+void use_symbols(const int *lhs, const int *rhs) {
clang_analyzer_eval(lhs < rhs); // expected-warning{{UNKNOWN}}
if (lhs < rhs)
return;
@@ -180,7 +180,7 @@
clang_analyzer_eval((lhs - rhs) == 5); // expected-warning{{TRUE}}
}
-void equal_implies_zero(int *lhs, int *rhs) {
+void equal_implies_zero(const int *lhs, const int *rhs) {
clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}}
if (lhs == rhs) {
clang_analyzer_eval(lhs != rhs); // expected-warning{{FALSE}}
@@ -192,7 +192,7 @@
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
}
-void zero_implies_equal(int *lhs, int *rhs) {
+void zero_implies_equal(const int *lhs, const int *rhs) {
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}}
if ((rhs - lhs) == 0) {
clang_analyzer_eval(lhs != rhs); // expected-warning{{FALSE}}
@@ -204,7 +204,7 @@
clang_analyzer_eval(lhs != rhs); // expected-warning{{TRUE}}
}
-void comparisons_imply_size(int *lhs, int *rhs) {
+void comparisons_imply_size(const int *lhs, const int *rhs) {
clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
if (lhs > rhs) {
@@ -226,7 +226,7 @@
clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
}
-void size_implies_comparison(int *lhs, int *rhs) {
+void size_implies_comparison(const int *lhs, const int *rhs) {
clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
if ((rhs - lhs) < 0) {
@@ -252,7 +252,7 @@
// False positives
//-------------------------------
-void zero_implies_reversed_equal(int *lhs, int *rhs) {
+void zero_implies_reversed_equal(const int *lhs, const int *rhs) {
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}}
if ((rhs - lhs) == 0) {
// FIXME: Should be FALSE.
@@ -268,7 +268,7 @@
clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
}
-void canonical_equal(int *lhs, int *rhs) {
+void canonical_equal(const int *lhs, const int *rhs) {
clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}}
if (lhs == rhs) {
// FIXME: Should be TRUE.
Index: test/Analysis/pr22954.c
===================================================================
--- test/Analysis/pr22954.c
+++ test/Analysis/pr22954.c
@@ -549,7 +549,7 @@
char * s2;
};
-int f263(int n, char * len) {
+int f263(int n, const char * len) {
struct xx x263 = {0};
x263.s2 = strdup("hello");
char input[] = {'a', 'b', 'c', 'd'};
Index: test/Analysis/objc-boxing.m
===================================================================
--- test/Analysis/objc-boxing.m
+++ test/Analysis/objc-boxing.m
@@ -39,7 +39,7 @@
return @(strdup("boxed dynamic string")); // expected-warning{{Potential memory leak}}
}
-id const_char_pointer(int *x) {
+id const_char_pointer(const int *x) {
if (x)
return @(3);
return @(*x); // expected-warning {{Dereference of null pointer (loaded from variable 'x')}}
Index: test/Analysis/null-deref-ps.c
===================================================================
--- test/Analysis/null-deref-ps.c
+++ test/Analysis/null-deref-ps.c
@@ -27,7 +27,7 @@
return p->x++; // expected-warning{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}}
}
-int f3(char* x) {
+int f3(const char* x) {
int i = 2;
Index: test/Analysis/misc-ps.m
===================================================================
--- test/Analysis/misc-ps.m
+++ test/Analysis/misc-ps.m
@@ -261,7 +261,7 @@
// Check that the pointer-to-conts arguments do not get invalidated by Obj C
// interfaces. radar://10595327
-int rdar_10595327(char *str) {
+int rdar_10595327(const char *str) {
char fl = str[0];
int *p = 0;
NSString *s = [NSString stringWithUTF8String:str];
Index: test/Analysis/misc-ps.c
===================================================================
--- test/Analysis/misc-ps.c
+++ test/Analysis/misc-ps.c
@@ -21,39 +21,39 @@
}
-int PR8962 (int *t) {
+int PR8962 (const int *t) {
// This should look through the __extension__ no-op.
if (__extension__ (t)) return 0;
return *t; // expected-warning {{null pointer}}
}
-int PR8962_b (int *t) {
+int PR8962_b (const int *t) {
// This should still ignore the nested casts
// which aren't handled by a single IgnoreParens()
if (((int)((int)t))) return 0;
return *t; // expected-warning {{null pointer}}
}
-int PR8962_c (int *t) {
+int PR8962_c (const int *t) {
// If the last element in a StmtExpr was a ParenExpr, it's still live
if (({ (t ? (_Bool)0 : (_Bool)1); })) return 0;
return *t; // no-warning
}
-int PR8962_d (int *t) {
+int PR8962_d (const int *t) {
// If the last element in a StmtExpr is an __extension__, it's still live
if (({ __extension__(t ? (_Bool)0 : (_Bool)1); })) return 0;
return *t; // no-warning
}
-int PR8962_e (int *t) {
+int PR8962_e (const int *t) {
// Redundant casts can mess things up!
// Environment used to skip through NoOp casts, but LiveVariables didn't!
if (({ (t ? (int)(int)0L : (int)(int)1L); })) return 0;
return *t; // no-warning
}
-int PR8962_f (int *t) {
+int PR8962_f (const int *t) {
// The StmtExpr isn't a block-level expression here,
// the __extension__ is. But the value should be attached to the StmtExpr
// anyway. Make sure the block-level check is /before/ IgnoreParens.
Index: test/Analysis/misc-ps-region-store.m
===================================================================
--- test/Analysis/misc-ps-region-store.m
+++ test/Analysis/misc-ps-region-store.m
@@ -448,7 +448,7 @@
//===----------------------------------------------------------------------===//
// Exercise creating ElementRegion with symbolic super region.
//===----------------------------------------------------------------------===//
-void element_region_with_symbolic_superregion(int* p) {
+void element_region_with_symbolic_superregion(const int* p) {
int *x;
int a;
if (p[0] == 1)
Index: test/Analysis/malloc.c
===================================================================
--- test/Analysis/malloc.c
+++ test/Analysis/malloc.c
@@ -961,7 +961,7 @@
}
extern void exit(int) __attribute__ ((__noreturn__));
-void mallocExit(int *g) {
+void mallocExit(const int *g) {
struct xx *p = malloc(12);
if (g != 0)
exit(1);
@@ -974,7 +974,7 @@
__attribute__ ((__noreturn__));
#define assert(expr) \
((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
-void mallocAssert(int *g) {
+void mallocAssert(const int *g) {
struct xx *p = malloc(12);
assert(g != 0);
@@ -1030,7 +1030,7 @@
} // expected-warning {{Potential memory leak}}
// Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p.
-void symbolLostWithStrcpy(char *s) {
+void symbolLostWithStrcpy(const char *s) {
char *p = malloc(12);
p = strcpy(p, s);
free(p);
@@ -1044,7 +1044,7 @@
return __builtin___strcpy_chk (__dest, __src, __builtin_object_size (__dest, 2 > 1));
}
-void symbolLostWithStrcpy_InlineStrcpyVersion(char *s) {
+void symbolLostWithStrcpy_InlineStrcpyVersion(const char *s) {
char *p = malloc(12);
p = ((__builtin_object_size (p, 0) != (size_t) -1) ? __builtin___strcpy_chk (p, s, __builtin_object_size (p, 2 > 1)) : __inline_strcpy_chk (p, s));
free(p);
@@ -1440,7 +1440,7 @@
}
-char *testLeakWithinReturn(char *str) {
+char *testLeakWithinReturn(const char *str) {
return strdup(strdup(str)); // expected-warning{{leak}}
}
Index: test/Analysis/logical-ops.c
===================================================================
--- test/Analysis/logical-ops.c
+++ test/Analysis/logical-ops.c
@@ -2,15 +2,15 @@
void clang_analyzer_eval(int);
-void testAnd(int i, int *p) {
+void testAnd(int i, const int *p) {
int *nullP = 0;
int *knownP = &i;
clang_analyzer_eval((knownP && knownP) == 1); // expected-warning{{TRUE}}
clang_analyzer_eval((knownP && nullP) == 0); // expected-warning{{TRUE}}
clang_analyzer_eval((knownP && p) == 1); // expected-warning{{UNKNOWN}}
}
-void testOr(int i, int *p) {
+void testOr(int i, const int *p) {
int *nullP = 0;
int *knownP = &i;
clang_analyzer_eval((nullP || knownP) == 1); // expected-warning{{TRUE}}
@@ -27,7 +27,7 @@
}
// These crashed the analyzer at some point.
-int between(char *x) {
+int between(const char *x) {
extern char start[];
extern char end[];
return x >= start && x < end;
Index: test/Analysis/inlining/path-notes.m
===================================================================
--- test/Analysis/inlining/path-notes.m
+++ test/Analysis/inlining/path-notes.m
@@ -136,7 +136,7 @@
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'x')}}
}
-void testNilReceiver(id *x) {
+void testNilReceiver(const id *x) {
if (*x) {
// expected-note@-1 {{Taking false branch}}
return;
Index: test/Analysis/inlining/inline-defensive-checks.c
===================================================================
--- test/Analysis/inlining/inline-defensive-checks.c
+++ test/Analysis/inlining/inline-defensive-checks.c
@@ -1,45 +1,45 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
// Perform inline defensive checks.
-void idc(int *p) {
+void idc(const int *p) {
if (p)
;
}
-int test01(int *p) {
+int test01(const int *p) {
if (p)
;
return *p; // expected-warning {{Dereference of null pointer}}
}
-int test02(int *p, int *x) {
+int test02(const int *p, const int *x) {
if (p)
;
idc(p);
if (x)
;
return *p; // expected-warning {{Dereference of null pointer}}
}
-int test03(int *p, int *x) {
+int test03(const int *p, int *x) {
idc(p);
if (p)
;
return *p; // False negative
}
-int deref04(int *p) {
+int deref04(const int *p) {
return *p; // expected-warning {{Dereference of null pointer}}
}
-int test04(int *p) {
+int test04(const int *p) {
if (p)
;
idc(p);
return deref04(p);
}
-int test11(int *q, int *x) {
+int test11(int *q, const int *x) {
int *p = q;
if (q)
;
@@ -60,24 +60,24 @@
return *p;
}
-int test21(int *q, int *x) {
+int test21(int *q, const int *x) {
if (q)
;
if (x)
;
int *p = q;
return *p; // expected-warning{{Dereference of null pointer}}
}
-int test22(int *q, int *x) {
+int test22(int *q, const int *x) {
idc(q);
if (x)
;
int *p = q;
return *p;
}
-int test23(int *q, int *x) {
+int test23(int *q, const int *x) {
idc(q);
if (x)
;
Index: test/Analysis/inlining/false-positive-suppression.c
===================================================================
--- test/Analysis/inlining/false-positive-suppression.c
+++ test/Analysis/inlining/false-positive-suppression.c
@@ -222,7 +222,7 @@
#endif
}
-int derefArg(int *p) {
+int derefArg(const int *p) {
return *p;
#ifndef SUPPRESSED
// expected-warning@-2 {{Dereference of null pointer}}
@@ -233,7 +233,7 @@
derefArg(cond ? &x : getNull());
}
-int derefArgCast(char *p) {
+int derefArgCast(const char *p) {
return *p;
#ifndef SUPPRESSED
// expected-warning@-2 {{Dereference of null pointer}}
@@ -244,7 +244,7 @@
derefArgCast((char*)((unsigned)cond ? &x : getNull()));
}
-int derefAssignment(int *p) {
+int derefAssignment(const int *p) {
return *p;
#ifndef SUPPRESSED
// expected-warning@-2 {{Dereference of null pointer}}
Index: test/Analysis/coverage.c
===================================================================
--- test/Analysis/coverage.c
+++ test/Analysis/coverage.c
@@ -4,7 +4,7 @@
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
-static int another_function(int *y) {
+static int another_function(const int *y) {
if (*y > 0)
return *y;
return 0;
Index: test/Analysis/casts.c
===================================================================
--- test/Analysis/casts.c
+++ test/Analysis/casts.c
@@ -54,7 +54,7 @@
// Test cast VariableSizeArray to pointer does not crash.
void *memcpy(void *, void const *, unsigned long);
typedef unsigned char Byte;
-void doit(char *data, int len) {
+void doit(const char *data, int len) {
if (len) {
Byte buf[len];
memcpy(buf, data, len);
@@ -76,7 +76,7 @@
return 0;
}
-int foo (int* p) {
+int foo (const int* p) {
int y = 0;
if (p == 0) {
if ((*((void**)&p)) == (void*)0) // Test that the cast to void preserves the symbolic region.
Index: test/Analysis/bstring.c
===================================================================
--- test/Analysis/bstring.c
+++ test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -302,7 +302,7 @@
clang_analyzer_eval(result == a); // no-warning (above is fatal)
}
-void mempcpy_unknownable_size (char *src, float n) {
+void mempcpy_unknownable_size (const char *src, float n) {
char a[4];
// This used to crash because we don't model floats.
mempcpy(a, src, (size_t)n);
Index: test/Analysis/NoReturn.m
===================================================================
--- test/Analysis/NoReturn.m
+++ test/Analysis/NoReturn.m
@@ -46,16 +46,16 @@
// Test cases.
//===----------------------------------------------------------------------===//
-int f1(int *x, NSString* s) {
+int f1(const int *x, NSString* s) {
if (x) ++x;
[NSException raise:@"Blah" format:[NSString stringWithFormat:@"Blah %@", s]];
return *x; // no-warning
}
-int f2(int *x, ...) {
+int f2(const int *x, ...) {
if (x) ++x;
va_list alist;
@@ -66,7 +66,7 @@
return *x; // no-warning
}
-int f3(int* x) {
+int f3(const int* x) {
if (x) ++x;
@@ -79,7 +79,7 @@
@interface CustomException : NSException
@end
-int testCustomException(int *x) {
+int testCustomException(const int *x) {
if (x != 0) return 0;
[CustomException raise:@"Blah" format:@"abc"];
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -501,6 +501,8 @@
D->setImplicit(Record[Idx++]);
D->Used = Record[Idx++];
D->setReferenced(Record[Idx++]);
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ VD->setNonConstUse();
D->setTopLevelDeclInObjCContainer(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
D->FromASTFile = true;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3632,6 +3632,7 @@
if (OldVar->isUsed(false))
NewVar->setIsUsed();
NewVar->setReferenced(OldVar->isReferenced());
+ NewVar->setNonConstUse();
}
InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope);
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -499,6 +499,7 @@
SourceLocation Loc,
bool RefersToCapture = false) {
D->setReferenced();
+ D->setNonConstUse();
D->markUsed(S.Context);
return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(),
SourceLocation(), D, RefersToCapture, Loc, Ty,
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -815,7 +815,8 @@
VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
Loc, Id, InitCaptureType, TSI, SC_Auto);
NewVD->setInitCapture(true);
- NewVD->setReferenced(true);
+ NewVD->setReferenced();
+ NewVD->setNonConstUse();
NewVD->markUsed(Context);
NewVD->setInit(Init);
return NewVD;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -9502,6 +9502,8 @@
if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType();
+ MarkLNonConstUse(LHSExpr);
+
QualType LHSType = LHSExpr->getType();
QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() :
CompoundType;
@@ -12807,7 +12809,8 @@
CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
DeclRefType, VK_LValue, Loc);
- Var->setReferenced(true);
+ Var->setReferenced();
+ Var->setNonConstUse();
Var->markUsed(S.Context);
}
@@ -14541,3 +14544,102 @@
return new (Context)
ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc);
}
+
+/// \brief Mark variables in l-value expression as nonconstuse
+void Sema::MarkLNonConstUse(Expr *E) {
+ E = E->IgnoreParenCasts();
+ if (auto *B = dyn_cast<BinaryOperator>(E)) {
+ if (B->isAdditiveOp()) {
+ // p + 2
+ MarkLNonConstUse(B->getLHS());
+ MarkLNonConstUse(B->getRHS());
+ } else if (B->isAssignmentOp()) {
+ MarkLNonConstUse(B->getLHS());
+ MarkRNonConstUse(B->getRHS());
+ }
+ } else if (auto *D = dyn_cast<DeclRefExpr>(E)) {
+ if (auto *VD = dyn_cast<VarDecl>(D->getDecl()))
+ VD->setNonConstUse();
+ } else if (auto *U = dyn_cast<UnaryOperator>(E)) {
+ MarkLNonConstUse(U->getSubExpr());
+ } else if (auto *A = dyn_cast<ArraySubscriptExpr>(E)) {
+ MarkLNonConstUse(A->getBase());
+ }
+}
+
+/// Mark variables in r-value expression as nonconstuse. Taking address of
+/// pointer is nonconstuse 'x=p' but dereferencing pointer is not nonconstuse
+/// 'x = *p;'
+void Sema::MarkRNonConstUse(Expr *E) {
+ E = E->IgnoreParenCasts();
+ if (auto *B = dyn_cast<BinaryOperator>(E)) {
+ if (B->isAdditiveOp()) {
+ // p + 2
+ MarkRNonConstUse(B->getLHS());
+ MarkRNonConstUse(B->getRHS());
+ } else if (B->isAssignmentOp()) {
+ MarkLNonConstUse(B->getLHS());
+ MarkRNonConstUse(B->getRHS());
+ }
+ } else if (auto *ILE = dyn_cast<InitListExpr>(E)) {
+ for (auto *I : llvm::make_range(ILE->getInits(),
+ ILE->getInits() + ILE->getNumInits()))
+ MarkRNonConstUse(I);
+ } else if (auto *CE = dyn_cast<CallExpr>(E)) {
+ // Mark nonconst function parameters as written.
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD || FD->isVariadic()) {
+ // Mark all arguments as written
+ // TODO: Handle CXXMemberCallExpr better
+ for (auto *Arg : CE->arguments()) {
+ MarkRNonConstUse(Arg);
+ }
+ return;
+ }
+ unsigned ArgNr = 0U;
+ for (const auto *Par : FD->parameters()) {
+ if (ArgNr >= CE->getNumArgs())
+ break;
+ // Is this a nonconstant pointer/reference parameter?
+ const Type *ParType = Par->getType().getTypePtr();
+ if ((ParType->isPointerType() &&
+ !ParType->getPointeeType().isConstQualified()) ||
+ (ParType->isReferenceType() && !Par->getType().isConstQualified()) ||
+ (ParType->isRecordType() && !Par->getType().isConstQualified())) {
+ // This is a nonconst pointer/reference parameter, the data is
+ // potentially written in the function.
+ Expr *Arg = CE->getArg(ArgNr);
+ if (ParType->isReferenceType()) {
+ if (auto *U = dyn_cast<UnaryOperator>(Arg))
+ Arg = U->getSubExpr();
+ } else if (auto *CE =
+ dyn_cast<CompoundLiteralExpr>(Arg->IgnoreParenCasts())) {
+ MarkRNonConstUse(CE->getInitializer());
+ return;
+ }
+ MarkRNonConstUse(Arg);
+ }
+ ArgNr++;
+ }
+ } else if (auto *B = dyn_cast<BinaryConditionalOperator>(E)) {
+ MarkRNonConstUse(B->getCommon());
+ MarkRNonConstUse(B->getFalseExpr());
+ } else if (auto *C = dyn_cast<ConditionalOperator>(E)) {
+ MarkRNonConstUse(C->getTrueExpr());
+ MarkRNonConstUse(C->getFalseExpr());
+ } else if (auto *D = dyn_cast<DeclRefExpr>(E)) {
+ if (auto *VD = dyn_cast<VarDecl>(D->getDecl()))
+ VD->setNonConstUse();
+ } else if (auto *U = dyn_cast<UnaryOperator>(E)) {
+ if (U->getOpcode() == UO_Deref)
+ return;
+ E = U->getSubExpr()->IgnoreParenCasts();
+ if (auto *A = dyn_cast<ArraySubscriptExpr>(E))
+ E = A->getBase();
+ else if (auto *U = dyn_cast<UnaryOperator>(E)) {
+ if (U->getOpcode() == UO_Deref)
+ E = U->getSubExpr()->IgnoreParenCasts();
+ }
+ MarkRNonConstUse(E);
+ }
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8987,6 +8987,12 @@
return;
}
+ if (const auto *VD = dyn_cast<VarDecl>(RealDecl)) {
+ const Type *T = VD->getType().getTypePtrOrNull();
+ if (T && (!T->isPointerType() || !T->getPointeeType().isConstQualified()))
+ MarkLNonConstUse(Init);
+ }
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
// Pure-specifiers are handled in ActOnPureSpecifier.
Diag(Method->getLocation(), diag::err_member_function_initialization)
@@ -10398,6 +10404,44 @@
}
}
+void Sema::DiagnoseNonConstPointerParameters(ParmVarDecl * const *ParamBegin,
+ ParmVarDecl * const *ParamEnd) {
+ // Don't diagnose nonconst-parameter errors in template instantiations
+ if (!ActiveTemplateInstantiations.empty())
+ return;
+ for (const auto *Param : llvm::make_range(ParamBegin, ParamEnd)) {
+ if (!Param->isReferenced() || Param->hasNonConstUse())
+ continue;
+ const Type *T = Param->getType().getTypePtr();
+ if (!T->isPointerType())
+ continue;
+ if (T->getPointeeType().isConstQualified())
+ continue;
+ // Don't warn about function pointers.
+ if (T->getPointeeType().getTypePtr()->isFunctionProtoType())
+ continue;
+ // Don't warn about struct parameters. These are not handled properly by
+ // the code currently. There should not be warnings always when a struct
+ // pointer parameter can be const neither.
+ if (T->getPointeeType().getTypePtr()->isRecordType())
+ continue;
+ // Don't warn about ** parameters. These are not handled properly by the
+ // code currently.
+ if (T->getPointeeType().getTypePtr()->isPointerType())
+ continue;
+ // Don't warn about void * as such parameters are often used in casts that
+ // are hard to handle well. For now there are no warnings about such
+ // parameters.
+ if (T->getPointeeType().getTypePtr()->isVoidType())
+ continue;
+ // Don't warn about _Atomic parameters
+ if (T->getPointeeType().getTypePtr()->isAtomicType())
+ continue;
+ Diag(Param->getLocation(), diag::warn_nonconst_parameter)
+ << Param->getDeclName();
+ }
+}
+
void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
ParmVarDecl * const *ParamEnd,
QualType ReturnTy,
@@ -10970,15 +11014,17 @@
// Don't diagnose unused parameters of defaulted or deleted functions.
if (!FD->isDeleted() && !FD->isDefaulted())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
+ if (!getLangOpts().CPlusPlus)
+ DiagnoseNonConstPointerParameters(FD->param_begin(), FD->param_end());
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
FD->getReturnType(), FD);
// If this is a structor, we need a vtable.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Destructor->getParent());
-
+
// Try to apply the named return value optimization. We have to check
// if we can do this here because lambdas keep return statements around
// to deduce an implicit return type.
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -389,6 +389,9 @@
return Actions.ActOnExprStmtError();
}
+ // Mark pointers in the expression as nonconstused.
+ Sema::MarkRNonConstUse(Expr.get());
+
if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
Actions.CheckCaseExpression(Expr.get())) {
// If a constant expression is followed by a colon inside a switch block,
@@ -954,6 +957,19 @@
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, false);
+ if (!R.isInvalid() && R.get()) {
+ if (ReturnStmt *RS = dyn_cast<ReturnStmt>(R.get())) {
+ if (RS->getRetValue()) {
+ if (auto *Cast = dyn_cast<ImplicitCastExpr>(RS->getRetValue())) {
+ const Type *T = Cast->getType().getTypePtr();
+ if (T->isPointerType() &&
+ !T->getPointeeType().isConstQualified()) {
+ Sema::MarkRNonConstUse(Cast);
+ }
+ }
+ }
+ }
+ }
} else {
// __extension__ can start declarations and it can also be a unary
// operator for expressions. Consume multiple __extension__ markers here
@@ -1825,6 +1841,14 @@
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
return StmtError();
}
+ // If function returns a nonconst pointer then pointers used in the return
+ // expression can't be const.
+ if (const FunctionDecl *FD = Actions.getCurFunctionDecl()) {
+ const Type *FnRetType = FD->getReturnType().getTypePtr();
+ if (FnRetType && FnRetType->isPointerType() &&
+ !FnRetType->getPointeeType().isConstQualified())
+ Sema::MarkRNonConstUse(R.get());
+ }
}
return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
}
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -167,7 +167,24 @@
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
/*isAddressOfOperand=*/false,
isTypeCast);
- return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
+
+ ExprResult ER(ParseRHSOfBinaryExpression(LHS, prec::Assignment));
+ if (ER.isInvalid())
+ return ER;
+
+ Expr *E = ER.get()->IgnoreParenCasts();
+ if (auto *B = dyn_cast<BinaryOperator>(E)) {
+ if (B->isAssignmentOp()) {
+ Sema::MarkLNonConstUse(B->getLHS());
+ Sema::MarkRNonConstUse(B->getRHS());
+ }
+ } else if (isa<CallExpr>(E) ||
+ isa<BinaryConditionalOperator>(E) ||
+ isa<ConditionalOperator>(E) ||
+ isa<UnaryOperator>(E)) {
+ Sema::MarkRNonConstUse(E);
+ }
+ return ER;
}
/// \brief Parse an assignment expression where part of an Objective-C message
@@ -408,6 +425,9 @@
if (TernaryMiddle.isUsable())
TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
LHS = ExprError();
+ } else if (auto *B = dyn_cast<BinaryOperator>(RHS.get())) {
+ if (B->isAssignmentOp())
+ Sema::MarkRNonConstUse(B->getRHS());
}
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
@@ -1543,6 +1563,8 @@
LHS = Actions.ActOnCallExpr(getCurScope(), LHS.get(), Loc,
ArgExprs, Tok.getLocation(),
ExecConfig);
+ if (!LHS.isInvalid())
+ Sema::MarkRNonConstUse(LHS.get());
PT.consumeClose();
}
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -2020,6 +2020,16 @@
ExprResult Init(ParseInitializer());
+ if (ThisDecl && !Init.isInvalid()) {
+ if (const auto *VD = dyn_cast<VarDecl>(ThisDecl)) {
+ const Type *T = VD->getType().getTypePtrOrNull();
+ if (T && (!T->isPointerType() ||
+ !T->getPointeeType().isConstQualified())) {
+ Sema::MarkRNonConstUse(Init.get());
+ }
+ }
+ }
+
// If this is the only decl in (possibly) range based for statement,
// our best guess is that the user meant ':' instead of '='.
if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) {
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1762,7 +1762,7 @@
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass SC)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
- redeclarable_base(C), Init() {
+ redeclarable_base(C), Init(), NonConstUse(false) {
static_assert(sizeof(VarDeclBitfields) <= sizeof(unsigned),
"VarDeclBitfields too large!");
static_assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned),
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1762,6 +1762,11 @@
void DiagnoseUnusedParameters(ParmVarDecl * const *Begin,
ParmVarDecl * const *End);
+ /// \brief Diagnose pointer parameters that should be const in the given
+ /// sequence of ParmVarDecl pointers.
+ void DiagnoseNonConstPointerParameters(ParmVarDecl * const *Begin,
+ ParmVarDecl * const *End);
+
/// \brief Diagnose whether the size of parameters or return value of a
/// function or obj-c method definition is pass-by-value and larger than a
/// specified threshold.
@@ -3560,6 +3565,12 @@
void MarkDeclRefReferenced(DeclRefExpr *E);
void MarkMemberReferenced(MemberExpr *E);
+ /// \brief Mark pointers in l-value expression as NonConstUse.
+ static void MarkLNonConstUse(Expr *E);
+
+ /// \brief Mark pointers in r-value expression as NonConstUse.
+ static void MarkRNonConstUse(Expr *E);
+
void UpdateMarkingForLValueToRValue(Expr *E);
void CleanupVarDeclMarking();
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -197,6 +197,8 @@
def err_parameter_name_omitted : Error<"parameter name omitted">;
def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
+def warn_nonconst_parameter : Warning<"parameter %0 can be const">,
+ InGroup<NonConstParameter>;
def warn_unused_variable : Warning<"unused variable %0">,
InGroup<UnusedVariable>, DefaultIgnore;
def warn_unused_local_typedef : Warning<
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -434,6 +434,7 @@
def UnusedLabel : DiagGroup<"unused-label">;
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedResult : DiagGroup<"unused-result">;
+def NonConstParameter : DiagGroup<"nonconst-parameter">;
def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">;
def UnevaluatedExpression : DiagGroup<"unevaluated-expression",
[PotentiallyEvaluatedExpression]>;
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -850,6 +850,9 @@
return getMostRecentDecl();
}
+ /// \brief Whether this variable has non-const use so it can't be const.
+ unsigned NonConstUse:1;
+
public:
typedef redeclarable_base::redecl_range redecl_range;
typedef redeclarable_base::redecl_iterator redecl_iterator;
@@ -865,6 +868,13 @@
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S);
+ /// \brief Whether the declared symbol has non-const usage so it can't be
+ /// const.
+ bool hasNonConstUse() const { return NonConstUse; }
+
+ /// \brief Use this method when this symbol can't be const.
+ void setNonConstUse() { NonConstUse = isThisDeclarationReferenced(); }
+
static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
SourceRange getSourceRange() const override LLVM_READONLY;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits