Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -642,7 +642,28 @@ if (const RecordType *R = CT->getAs()) if (R->hasConstFields()) return Cl::CM_ConstQualifiedField; - + // CXXThis can't point to const marked field of the given class + // to be modifiable + while (true) { + if (const MemberExpr *ME = dyn_cast(E)) { + E = ME->getBase()->IgnoreParenImpCasts(); + continue; + } else if (const ArraySubscriptExpr *ASE = + dyn_cast(E)) { + E = ASE->getBase()->IgnoreParenImpCasts(); + continue; + } else if (const ExtVectorElementExpr *EVE = + dyn_cast(E)) { + E = EVE->getBase()->IgnoreParenImpCasts(); + continue; + } else if (const CXXThisExpr *CXXThis = dyn_cast(E)) { + CT = Ctx.getCanonicalType( + CXXThis->getType().getTypePtr()->getPointeeType()); + if (CT.isConstQualified()) + return Cl::CM_ConstQualified; + } + break; + } return Cl::CM_Modifiable; } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -10321,7 +10321,7 @@ /// 'const' due to being captured within a block? enum NonConstCaptureKind { NCCK_None, NCCK_Block, NCCK_Lambda }; static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { - assert(E->isLValue() && E->getType().isConstQualified()); + assert(E->isLValue()); E = E->IgnoreParens(); // Must be a reference to a declaration from an enclosing scope. @@ -10401,10 +10401,8 @@ const ValueDecl *VD = ME->getMemberDecl(); if (const FieldDecl *Field = dyn_cast(VD)) { // Mutable fields can be modified even if the class is const. - if (Field->isMutable()) { - assert(DiagnosticEmitted && "Expected diagnostic not emitted."); + if (Field->isMutable()) break; - } if (!IsTypeModifiable(Field->getType(), IsDereference)) { if (!DiagnosticEmitted) { @@ -10434,8 +10432,16 @@ // Static fields do not inherit constness from parents. break; } - break; - } // End MemberExpr + break; // End MemberExpr + } else if (const ArraySubscriptExpr *ASE = + dyn_cast(E)) { + E = ASE->getBase()->IgnoreParenImpCasts(); + continue; + } else if (const ExtVectorElementExpr *EVE = + dyn_cast(E)) { + E = EVE->getBase()->IgnoreParenImpCasts(); + continue; + } break; } Index: test/Sema/assign.c =================================================================== --- test/Sema/assign.c +++ test/Sema/assign.c @@ -11,10 +11,10 @@ typedef int arr[10]; void test3() { - const arr b; - const int b2[10]; - b[4] = 1; // expected-error {{read-only variable is not assignable}} - b2[4] = 1; // expected-error {{read-only variable is not assignable}} + const arr b; // expected-note {{variable 'b' declared const here}} + const int b2[10]; // expected-note {{variable 'b2' declared const here}} + b[4] = 1; // expected-error {{cannot assign to variable 'b' with const-qualified type 'const arr' (aka 'int const[10]')}} + b2[4] = 1; // expected-error {{cannot assign to variable 'b2' with const-qualified type 'const int [10]'}} } typedef struct I { Index: test/Sema/typedef-retain.c =================================================================== --- test/Sema/typedef-retain.c +++ test/Sema/typedef-retain.c @@ -16,8 +16,8 @@ typedef int a[5]; void test3() { typedef const a b; - b r; - r[0]=10; // expected-error {{read-only variable is not assignable}} + b r; // expected-note {{variable 'r' declared const here}} + r[0]=10; // expected-error {{cannot assign to variable 'r' with const-qualified type 'b' (aka 'int const[5]')}} } int test4(const a y) { Index: test/SemaCXX/anonymous-union.cpp =================================================================== --- test/SemaCXX/anonymous-union.cpp +++ test/SemaCXX/anonymous-union.cpp @@ -40,7 +40,8 @@ } void X::test_unqual_references_const() const { // expected-note 2{{member function 'X::test_unqual_references_const' is declared const here}} - d = 0.0; + // TODO: it seems we should not see any error here becuase 'd' is mutable + d = 0.0; // expected-error {{read-only variable is not assignable}} f2 = 0; // expected-error{{cannot assign to non-static data member within const member function 'test_unqual_references_const'}} a = 0; // expected-error{{cannot assign to non-static data member within const member function 'test_unqual_references_const'}} } Index: test/SemaCXX/err_typecheck_assign_const.cpp =================================================================== --- test/SemaCXX/err_typecheck_assign_const.cpp +++ test/SemaCXX/err_typecheck_assign_const.cpp @@ -129,3 +129,23 @@ Func &bar(); bar()() = 0; // expected-error {{read-only variable is not assignable}} } + +typedef float float4 __attribute__((ext_vector_type(4))); +struct OhNo { + float4 v; + void AssignMe() const { v.x = 1; } // expected-error {{cannot assign to non-static data member within const member function 'AssignMe'}} \ + expected-note {{member function 'OhNo::AssignMe' is declared const here}} +}; + +typedef float float4_2 __attribute__((__vector_size__(16))); +struct OhNo2 { + float4_2 v; + void AssignMe() const { v[0] = 1; } // expected-error {{cannot assign to non-static data member within const member function 'AssignMe'}} \ + expected-note {{member function 'OhNo2::AssignMe' is declared const here}} +}; + +struct OhNo3 { + float v[4]; + void AssignMe() const { v[0] = 1; } // expected-error {{cannot assign to non-static data member within const member function 'AssignMe'}} \ + expected-note {{member function 'OhNo3::AssignMe' is declared const here}} +};