[PATCH] Add more information when displaying a "read-only variable is not assignable" error

Richard Smith richard at metafoo.co.uk
Thu Aug 14 16:04:38 PDT 2014


================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:4817
@@ +4816,3 @@
+  "%select{read-only variable is not assignable|"
+  "cannot assign to return value since function %1 returns a const value|"
+  "cannot assign to variable %1 with const qualified type %2|"
----------------
Please use 'because' rather than 'since'.

================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:4818-4819
@@ +4817,4 @@
+  "cannot assign to return value since function %1 returns a const value|"
+  "cannot assign to variable %1 with const qualified type %2|"
+  "cannot assign to data member %1 with const qualified type %2|"
+  "cannot assign to data member within const member function %1}0">;
----------------
There's a missing hyphen between "const" and "qualified" in both of these.

================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:4819-4820
@@ +4818,4 @@
+  "cannot assign to variable %1 with const qualified type %2|"
+  "cannot assign to data member %1 with const qualified type %2|"
+  "cannot assign to data member within const member function %1}0">;
+
----------------
You have "data member" here but "field" below. This should be consistently "field" (or "non-static data member") in both places.

================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:4823
@@ +4822,3 @@
+def note_typecheck_assign_const : Note<
+  "%select{|"
+  "function %1 which returns const qualified type %2 declared here|"
----------------
Can you put something like `ERROR` in here so that we don't just get "note: " if this is somehow produced? (We do this in a few other diagnostics which have %select's with missing options.)

================
Comment at: lib/Sema/SemaExpr.cpp:8485-8488
@@ -8484,1 +8484,6 @@
 
+// Emit the "read-only variable not assignable" error and print notes to give
+// more information about why the variable is not assignable, such as pointing
+// to the declaration of a const variable, showing that a method is const, or
+// that the funciton is returning a const reference.
+static void DiagnoseConstAssignment(Sema &S, const Expr *E,
----------------
`///` for this comment, please.

================
Comment at: lib/Sema/SemaExpr.cpp:8526-8533
@@ +8525,10 @@
+    // Class method is const.
+    if (isa<CXXThisExpr>(E)) {
+      if (const DeclContext *DC = S.getFunctionLevelDeclContext()) {
+        MD = dyn_cast<CXXMethodDecl>(DC);
+        if (MD && !MD->isConst()) {
+          MD = nullptr;
+        }
+      }
+    }
+  }
----------------
I don't think this does the right thing for a member reference within a lambda-expression (I think you'll pick up the wrong DC).

================
Comment at: lib/Sema/SemaExpr.cpp:8543-8545
@@ +8542,5 @@
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+    VD = DRE->getDecl();
+    if (VD && !VD->getType().isConstQualified())
+      VD = nullptr;
+  }
----------------
If we're in a lambda-expression and the variable got constified by lambda-capture, it'd be nice to point to the lambda and suggest that maybe it should be `mutable`. For simple cases, we seem to do that in `CheckForModifiableLvalue`, but not for member access cases. Maybe we should move more of the code from there into here?

================
Comment at: lib/Sema/SemaExpr.cpp:8548-8553
@@ +8547,8 @@
+
+  if (FD) {
+    PD << ConstFunction << FD;
+  } else if (VD) {
+    PD << ConstVariable << VD << VD->getType();
+  } else if (ME) {
+    PD << ConstField << ME->getMemberDecl() << ME->getType();
+  } else if (MD) {
----------------
I think `ME` should be first here (notionally, I think that the constness of the field is a more immediate problem than the fact that the function return type or the variable is declared `const`). This will also fix a bug in the current implementation with `mutable` members:

  struct A { const int n; };
  struct B { mutable A a; };
  extern const B b;
  void f() { b.a.n = 23; }

This should diagnose that `A::n` is `const`, but I think it'll incorrectly diagnose that `b` is `const` (which is irrelevant because `B::a` is `mutable`).

================
Comment at: lib/Sema/SemaExpr.cpp:8562-8588
@@ +8561,29 @@
+
+  if (FD) {
+    S.Diag(FD->getReturnTypeSourceRange().getBegin(),
+           diag::note_typecheck_assign_const)
+        << ConstFunction << FD << FD->getReturnType()
+        << FD->getReturnTypeSourceRange();
+  }
+
+  if (VD) {
+    S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
+        << ConstVariable << VD << VD->getType() << VD->getSourceRange();
+  }
+
+  if (ME) {
+    while (ME) {
+      ValueDecl *VD = ME->getMemberDecl();
+      if (VD->getType().isConstQualified()) {
+        S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
+            << ConstField << VD << VD->getType() << VD->getSourceRange();
+      }
+      ME = dyn_cast<MemberExpr>(ME->getBase());
+    }
+  }
+
+  if (MD) {
+    S.Diag(MD->getLocation(), diag::note_typecheck_assign_const)
+        << ConstMethod << MD << MD->getSourceRange();
+  }
+}
----------------
As noted above, these may be incorrect if we hit a `mutable` on the way.

http://reviews.llvm.org/D4479






More information about the cfe-commits mailing list