124 changes: 124 additions & 0 deletions clang/test/SemaCXX/err_typecheck_assign_const.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s

const int global = 5; // expected-note{{variable 'global' declared const here}}
void test1() {
global = 2; // expected-error{{cannot assign to variable 'global' with const-qualified type 'const int'}}
}

void test2 () {
const int local = 5; // expected-note{{variable 'local' declared const here}}
local = 0; // expected-error{{cannot assign to variable 'local' with const-qualified type 'const int'}}
}

void test2 (const int parameter) { // expected-note{{variable 'parameter' declared const here}}
parameter = 2; // expected-error{{cannot assign to variable 'parameter' with const-qualified type 'const int'}}
}

class test3 {
int field;
const int const_field = 1; // expected-note 2{{non-static data member 'const_field' declared const here}}
static const int static_const_field = 1; // expected-note 2{{variable 'static_const_field' declared const here}}
void test() {
const_field = 4; // expected-error{{cannot assign to non-static data member 'const_field' with const-qualified type 'const int'}}
static_const_field = 4; // expected-error{{cannot assign to variable 'static_const_field' with const-qualified type 'const int'}}
}
void test_const() const { // expected-note 2{{member function 'test3::test_const' is declared const here}}
field = 4; // expected-error{{cannot assign to non-static data member within const member function 'test_const'}}
const_field = 4 ; // expected-error{{cannot assign to non-static data member 'const_field' with const-qualified type 'const int'}}
static_const_field = 4; // expected-error{{cannot assign to variable 'static_const_field' with const-qualified type 'const int'}}
}
};

const int &return_const_ref(); // expected-note{{function 'return_const_ref' which returns const-qualified type 'const int &' declared here}}

void test4() {
return_const_ref() = 10; // expected-error{{cannot assign to return value because function 'return_const_ref' returns a const value}}
}

struct S5 {
int field;
const int const_field = 4; // expected-note {{non-static data member 'const_field' declared const here}}
};

void test5() {
S5 s5;
s5.field = 5;
s5.const_field = 5; // expected-error{{cannot assign to non-static data member 'const_field' with const-qualified type 'const int'}}
}

struct U1 {
int a = 5;
};

struct U2 {
U1 u1;
};

struct U3 {
const U2 u2 = U2(); // expected-note{{non-static data member 'u2' declared const here}}
};

struct U4 {
U3 u3;
};

void test6() {
U4 u4;
u4.u3.u2.u1.a = 5; // expected-error{{cannot assign to non-static data member 'u2' with const-qualified type 'const U2'}}
}

struct A {
int z;
};
struct B {
A a;
};
struct C {
B b;
C();
};
const C &getc(); // expected-note{{function 'getc' which returns const-qualified type 'const C &' declared here}}
void test7() {
const C c; // expected-note{{variable 'c' declared const here}}
c.b.a.z = 5; // expected-error{{cannot assign to variable 'c' with const-qualified type 'const C'}}

getc().b.a.z = 5; // expected-error{{cannot assign to return value because function 'getc' returns a const value}}
}

struct D { const int n; }; // expected-note 2{{non-static data member 'n' declared const here}}
struct E { D *const d = 0; };
void test8() {
extern D *const d;
d->n = 0; // expected-error{{cannot assign to non-static data member 'n' with const-qualified type 'const int'}}

E e;
e.d->n = 0; // expected-error{{cannot assign to non-static data member 'n' with const-qualified type 'const int'}}
}

struct F { int n; };
struct G { const F *f; }; // expected-note{{non-static data member 'f' declared const here}}
void test10() {
const F *f; // expected-note{{variable 'f' declared const here}}
f->n = 0; // expected-error{{cannot assign to variable 'f' with const-qualified type 'const F *'}}

G g;
g.f->n = 0; // expected-error{{cannot assign to non-static data member 'f' with const-qualified type 'const F *'}}
}

void test11(
const int x, // expected-note{{variable 'x' declared const here}}
const int& y // expected-note{{variable 'y' declared const here}}
) {
x = 5; // expected-error{{cannot assign to variable 'x' with const-qualified type 'const int'}}
y = 5; // expected-error{{cannot assign to variable 'y' with const-qualified type 'const int &'}}
}

struct H {
const int a = 0; // expected-note{{non-static data member 'a' declared const here}}
const int &b = a; // expected-note{{non-static data member 'b' declared const here}}
};

void test12(H h) {
h.a = 1; // expected-error {{cannot assign to non-static data member 'a' with const-qualified type 'const int'}}
h.b = 2; // expected-error {{cannot assign to non-static data member 'b' with const-qualified type 'const int &'}}
}
252 changes: 252 additions & 0 deletions clang/test/SemaCXX/err_typecheck_assign_const_filecheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// RUN: not %clang_cc1 -fsyntax-only -std=c++11 %s 2>&1 | FileCheck %s

struct E {
int num;
const int Cnum = 0;
mutable int Mnum;
static int Snum;
const static int CSnum;
};

struct D {
E e;
const E Ce;
mutable E Me;
static E Se;
const static E CSe;
E &getE() const;
const E &getCE() const;
};

struct C {
D d;
const D Cd;
mutable D Md;
static D Sd;
const static D CSd;
D &getD() const;
const D &getCD() const;
};

struct B {
C c;
const C Cc;
mutable C Mc;
static C Sc;
const static C CSc;
C &getC() const;
static C &getSC();
const C &getCC() const;
static const C &getSCC();
};

struct A {
B b;
const B Cb;
mutable B Mb;
static B Sb;
const static B CSb;
B &getB() const;
static B &getSB();
const B &getCB() const;
static const B &getSCB();
};

A& getA();

// Valid assignment
void test1(A a, const A Ca) {
a.b.c.d.e.num = 5;
a.b.c.d.e.Mnum = 5;
Ca.b.c.d.e.Mnum = 5;
a.b.c.d.e.Snum = 5;
Ca.b.c.d.e.Snum = 5;
Ca.b.c.Md.e.num = 5;
Ca.Mb.Cc.d.e.Mnum = 5;
Ca.Mb.getC().d.e.num = 5;
Ca.getSB().c.d.e.num = 5;
a.getSCB().c.d.Me.num = 5;
Ca.Cb.Cc.Cd.Ce.Snum = 5;
// CHECK-NOT: error:
// CHECK-NOT: note:
}

// One note
void test2(A a, const A Ca) {
Ca.b.c.d.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Ca'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ca'
// CHECK-NOT: note:

a.Cb.c.d.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cb'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cb'
// CHECK-NOT: note:

a.b.c.Cd.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cd'
// CHECK-NOT: note:

a.b.c.d.e.CSnum = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'CSnum'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'CSnum'
// CHECK-NOT: note:

a.b.c.d.e.Cnum = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cnum'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cnum'
// CHECK-NOT: note:

a.getCB().c.d.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'getCB'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'getCB'
// CHECK-NOT: note:

a.getSCB().c.d.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'getSCB'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'getSCB'
// CHECK-NOT: note:
}

// Two notes
void test3(A a, const A Ca) {

a.getSCB().Cc.d.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cc'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cc'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'getSCB'
// CHECK-NOT: note:

Ca.b.c.Cd.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ca'
// CHECK-NOT: note:

a.getCB().c.Cd.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'getCB'
// CHECK-NOT: note:

a.b.getCC().d.e.Cnum = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cnum'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cnum'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'getCC'
// CHECK-NOT: note:

a.b.c.Cd.Ce.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Ce'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ce'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cd'
// CHECK-NOT: note:

a.b.CSc.Cd.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'CSc'
// CHECK-NOT: note:

a.CSb.c.Cd.e.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Cd'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'CSb'
// CHECK-NOT: note:
}

// No errors
void test4(const A Ca) {
// Mutable cases
Ca.Mb.c.d.e.num = 5;
Ca.CSb.Mc.d.e.num = 5;
Ca.getCB().Mc.d.e.num = 5;
Ca.getSCB().Mc.d.e.num = 5;

// Returning non-const reference
Ca.getB().c.d.e.num = 5;
Ca.CSb.getC().d.e.num = 5;
Ca.getCB().getC().d.e.num = 5;
Ca.getSCB().getC().d.e.num = 5;

// Returning non-const reference
Ca.getSB().c.d.e.num = 5;
Ca.CSb.getSC().d.e.num = 5;
Ca.getCB().getSC().d.e.num = 5;
Ca.getSCB().getSC().d.e.num = 5;

// Static member
Ca.Sb.c.d.e.num = 5;
Ca.CSb.Sc.d.e.num = 5;
Ca.getCB().Sc.d.e.num = 5;
Ca.getSCB().Sc.d.e.num = 5;

// CHECK-NOT: error:
// CHECK-NOT: note:
}

// Only display notes for relavent cases.
void test5(const A Ca) {
Ca.Mb.c.d.Ce.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Ce'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ce'
// CHECK-NOT: note:

Ca.getB().c.d.Ce.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Ce'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ce'
// CHECK-NOT: note:

Ca.getSB().c.d.Ce.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Ce'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ce'
// CHECK-NOT: note:

Ca.Sb.c.d.Ce.num = 5;
// CHECK-NOT: error:
// CHECK: error:{{.*}} 'Ce'
// CHECK-NOT: note:
// CHECK: note:{{.*}} 'Ce'
// CHECK-NOT: note:
}
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/function-type-qual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class C {
x = 0;
}

void m2() const {
x = 0; // expected-error {{read-only variable is not assignable}}
void m2() const { // expected-note {{member function 'C::m2' is declared const here}}
x = 0; // expected-error {{cannot assign to non-static data member within const member function 'm2'}}
}

int x;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaObjC/arc.m
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ void test12(id collection) {
x = 0; // expected-error {{fast enumeration variables can't be modified in ARC by default; declare the variable __strong to allow this}}
}

for (const id x in collection) {
x = 0; // expected-error {{read-only variable is not assignable}}
for (const id x in collection) { // expected-note {{variable 'x' declared const here}}
x = 0; // expected-error {{cannot assign to variable 'x' with const-qualified type 'const __strong id'}}
}

for (__strong id x in collection) {
Expand Down
4 changes: 3 additions & 1 deletion clang/test/SemaTemplate/dependent-type-identity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ namespace PR18275 {
void A<T>::f(int x) { x = 0; }

template<typename T>
void A<T>::g(const int x) { x = 0; } // expected-error {{not assignable}}
void A<T>::g(const int x) { // expected-note {{declared const here}}
x = 0; // expected-error {{cannot assign to variable 'x'}}
}

template<typename T>
void A<T>::h(T) {} // FIXME: Should reject this. Type is different from prior decl if T is an array type.
Expand Down