danielmarjamaki updated this revision to Diff 37728.
danielmarjamaki marked an inline comment as done.
danielmarjamaki added a comment.

Fix FN for code:

const char *ret(char *p) {

  return p ? p : "";

}


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/FixIt/dereference-addressof.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,189 @@
+// 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) { // expected-warning {{parameter 'p' can be const}}
+  const int *q;
+  q = p;
+}
+
+void assign2(int *p) { // expected-warning {{parameter 'p' can be const}}
+  const int *q;
+  q = p + 1;
+}
+
+void assign3(int *p) {
+  *p = 0;
+}
+
+void assign4(char *p) {
+  p[0] = 0;
+}
+
+void assign5(int *p) {
+  int *q;
+  q = p++;
+}
+
+void assign6(char *p) {
+  char *a, *b;
+  a = b = p;
+}
+
+void assign7(char *a, char *b) {
+  char *x;
+  x = (a ? a : b);
+}
+
+void assign8(unsigned char *str, const unsigned int i) {
+    unsigned char *p;
+    for (p = str + i; *p; ) {}
+}
+
+void assign9(int *buf) {
+  int i, *p;
+  for (i=0, p=buf; i<10; i++, p++) {
+    *p = 1;
+  }
+}
+
+void assign10(int *p, int x) {
+  for (int *q = p+x-1; 0; q++);
+}
+
+
+void init1(int *p) { // expected-warning {{parameter 'p' can be const}}
+  const int *q = p;
+}
+
+void init2(int *p) { // expected-warning {{parameter 'p' can be const}}
+  const int *q = p + 1;
+}
+
+void init3(int *p) {
+  int *q = p;
+}
+
+void init4(float *p) {
+  int *q = (int *)p;
+}
+
+void init5(int *p) {
+  int *i = p ? p : 0;
+}
+
+void init6(int *p) {
+  int *a[] = {p,p,0};
+}
+
+
+int return1(int *p) { // expected-warning {{parameter 'p' can be const}}
+  return *p;
+}
+
+const int *return2(int *p) { // expected-warning {{parameter 'p' can be const}}
+  return p;
+}
+
+const int *return3(int *p) { // expected-warning {{parameter 'p' can be const}}
+  return p+1;
+}
+
+const char *return4(char *p) { // expected-warning {{parameter 'p' can be const}}
+  return p ? p : "";
+}
+
+char *return5(char *s) {
+  return s;
+}
+
+char *return6(char *s) {
+  return s+1;
+}
+
+char *return7(char *a, char *b) {
+  return a ? a : b;
+}
+
+char return8(int *p) {
+  return ++(*p);
+}
+
+
+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/FixIt/dereference-addressof.c
===================================================================
--- test/FixIt/dereference-addressof.c
+++ test/FixIt/dereference-addressof.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-nonconst-parameter %s
 // RUN: cp %s %t
 // RUN: not %clang_cc1 -fsyntax-only -fixit -x c %t
-// RUN: %clang_cc1 -fsyntax-only -pedantic -x c %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-nonconst-parameter -x c %t
 
 void ip(int *aPtr) {}   // expected-note{{passing argument to parameter 'aPtr' here}}
 void i(int a) {}        // expected-note{{passing argument to parameter 'a' here}}
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,105 @@
   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());
+      // If LHS is nonconst then mark RHS as nonconstuse
+      const Type *T = B->getLHS()->getType().getTypePtr();
+      if (T && T->isPointerType() && !T->getPointeeType().isConstQualified())
+        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,19 @@
   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::MarkRNonConstUse(E);
+  } else if (isa<CallExpr>(E) || isa<UnaryOperator>(E)) {
+    Sema::MarkRNonConstUse(E);
+  }
+  return ER;
 }
 
 /// \brief Parse an assignment expression where part of an Objective-C message
@@ -408,6 +420,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 +1558,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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to