@@ -8982,6 +8982,139 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
8982
8982
return (isa<BlockDecl>(DC) ? NCCK_Block : NCCK_Lambda);
8983
8983
}
8984
8984
8985
+ static bool IsTypeModifiable(QualType Ty, bool IsDereference) {
8986
+ Ty = Ty.getNonReferenceType();
8987
+ if (IsDereference && Ty->isPointerType())
8988
+ Ty = Ty->getPointeeType();
8989
+ return !Ty.isConstQualified();
8990
+ }
8991
+
8992
+ /// Emit the "read-only variable not assignable" error and print notes to give
8993
+ /// more information about why the variable is not assignable, such as pointing
8994
+ /// to the declaration of a const variable, showing that a method is const, or
8995
+ /// that the function is returning a const reference.
8996
+ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
8997
+ SourceLocation Loc) {
8998
+ // Update err_typecheck_assign_const and note_typecheck_assign_const
8999
+ // when this enum is changed.
9000
+ enum {
9001
+ ConstFunction,
9002
+ ConstVariable,
9003
+ ConstMember,
9004
+ ConstMethod,
9005
+ ConstUnknown, // Keep as last element
9006
+ };
9007
+
9008
+ SourceRange ExprRange = E->getSourceRange();
9009
+
9010
+ // Only emit one error on the first const found. All other consts will emit
9011
+ // a note to the error.
9012
+ bool DiagnosticEmitted = false;
9013
+
9014
+ // Track if the current expression is the result of a derefence, and if the
9015
+ // next checked expression is the result of a derefence.
9016
+ bool IsDereference = false;
9017
+ bool NextIsDereference = false;
9018
+
9019
+ // Loop to process MemberExpr chains.
9020
+ while (true) {
9021
+ IsDereference = NextIsDereference;
9022
+ NextIsDereference = false;
9023
+
9024
+ E = E->IgnoreParenImpCasts();
9025
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
9026
+ NextIsDereference = ME->isArrow();
9027
+ const ValueDecl *VD = ME->getMemberDecl();
9028
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) {
9029
+ // Mutable fields can be modified even if the class is const.
9030
+ if (Field->isMutable()) {
9031
+ assert(DiagnosticEmitted && "Expected diagnostic not emitted.");
9032
+ break;
9033
+ }
9034
+
9035
+ if (!IsTypeModifiable(Field->getType(), IsDereference)) {
9036
+ if (!DiagnosticEmitted) {
9037
+ S.Diag(Loc, diag::err_typecheck_assign_const)
9038
+ << ExprRange << ConstMember << false /*static*/ << Field
9039
+ << Field->getType();
9040
+ DiagnosticEmitted = true;
9041
+ }
9042
+ S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
9043
+ << ConstMember << false /*static*/ << Field << Field->getType()
9044
+ << Field->getSourceRange();
9045
+ }
9046
+ E = ME->getBase();
9047
+ continue;
9048
+ } else if (const VarDecl *VDecl = dyn_cast<VarDecl>(VD)) {
9049
+ if (VDecl->getType().isConstQualified()) {
9050
+ if (!DiagnosticEmitted) {
9051
+ S.Diag(Loc, diag::err_typecheck_assign_const)
9052
+ << ExprRange << ConstMember << true /*static*/ << VDecl
9053
+ << VDecl->getType();
9054
+ DiagnosticEmitted = true;
9055
+ }
9056
+ S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
9057
+ << ConstMember << true /*static*/ << VDecl << VDecl->getType()
9058
+ << VDecl->getSourceRange();
9059
+ }
9060
+ // Static fields do not inherit constness from parents.
9061
+ break;
9062
+ }
9063
+ break;
9064
+ } // End MemberExpr
9065
+ break;
9066
+ }
9067
+
9068
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
9069
+ // Function calls
9070
+ const FunctionDecl *FD = CE->getDirectCallee();
9071
+ if (!IsTypeModifiable(FD->getReturnType(), IsDereference)) {
9072
+ if (!DiagnosticEmitted) {
9073
+ S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange
9074
+ << ConstFunction << FD;
9075
+ DiagnosticEmitted = true;
9076
+ }
9077
+ S.Diag(FD->getReturnTypeSourceRange().getBegin(),
9078
+ diag::note_typecheck_assign_const)
9079
+ << ConstFunction << FD << FD->getReturnType()
9080
+ << FD->getReturnTypeSourceRange();
9081
+ }
9082
+ } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
9083
+ // Point to variable declaration.
9084
+ if (const ValueDecl *VD = DRE->getDecl()) {
9085
+ if (!IsTypeModifiable(VD->getType(), IsDereference)) {
9086
+ if (!DiagnosticEmitted) {
9087
+ S.Diag(Loc, diag::err_typecheck_assign_const)
9088
+ << ExprRange << ConstVariable << VD << VD->getType();
9089
+ DiagnosticEmitted = true;
9090
+ }
9091
+ S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
9092
+ << ConstVariable << VD << VD->getType() << VD->getSourceRange();
9093
+ }
9094
+ }
9095
+ } else if (isa<CXXThisExpr>(E)) {
9096
+ if (const DeclContext *DC = S.getFunctionLevelDeclContext()) {
9097
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
9098
+ if (MD->isConst()) {
9099
+ if (!DiagnosticEmitted) {
9100
+ S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange
9101
+ << ConstMethod << MD;
9102
+ DiagnosticEmitted = true;
9103
+ }
9104
+ S.Diag(MD->getLocation(), diag::note_typecheck_assign_const)
9105
+ << ConstMethod << MD << MD->getSourceRange();
9106
+ }
9107
+ }
9108
+ }
9109
+ }
9110
+
9111
+ if (DiagnosticEmitted)
9112
+ return;
9113
+
9114
+ // Can't determine a more specific message, so display the generic error.
9115
+ S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown;
9116
+ }
9117
+
8985
9118
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
8986
9119
/// emit an error and return true. If so, return false.
8987
9120
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
@@ -8998,8 +9131,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
8998
9131
bool NeedType = false;
8999
9132
switch (IsLV) { // C99 6.5.16p2
9000
9133
case Expr::MLV_ConstQualified:
9001
- DiagID = diag::err_typecheck_assign_const;
9002
-
9003
9134
// Use a specialized diagnostic when we're assigning to an object
9004
9135
// from an enclosing function or block.
9005
9136
if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) {
@@ -9038,13 +9169,20 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
9038
9169
if (Loc != OrigLoc)
9039
9170
Assign = SourceRange(OrigLoc, OrigLoc);
9040
9171
S.Diag(Loc, DiagID) << E->getSourceRange() << Assign;
9041
- // We need to preserve the AST regardless, so migration tool
9172
+ // We need to preserve the AST regardless, so migration tool
9042
9173
// can do its job.
9043
9174
return false;
9044
9175
}
9045
9176
}
9046
9177
}
9047
9178
9179
+ // If none of the special cases above are triggered, then this is a
9180
+ // simple const assignment.
9181
+ if (DiagID == 0) {
9182
+ DiagnoseConstAssignment(S, E, Loc);
9183
+ return true;
9184
+ }
9185
+
9048
9186
break;
9049
9187
case Expr::MLV_ArrayType:
9050
9188
case Expr::MLV_ArrayTemporary:
0 commit comments