[clang] [clang] Fix-it hint for `++this` -> `++*this` when deref is modifiable (PR #94159)

Rajveer Singh Bharadwaj via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 6 05:55:36 PDT 2024


https://github.com/Rajveer100 updated https://github.com/llvm/llvm-project/pull/94159

>From 5092ffd04d1eeefcd0e9708415d40886e112bc31 Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Sun, 2 Jun 2024 18:33:37 +0530
Subject: [PATCH] [clang] Fix-it hint for `++this` -> `++*this` when deref is
 modifiable

Resolves #93066
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +
 clang/lib/Sema/SemaExpr.cpp                   | 56 ++++++++++++++++++-
 clang/test/C/drs/dr1xx.c                      |  1 +
 clang/test/Sema/debug-93066.cpp               | 31 ++++++++++
 clang/test/Sema/exprs.c                       |  2 +
 clang/test/Sema/va_arg_x86_32.c               |  1 +
 clang/test/SemaObjCXX/sel-address.mm          |  1 +
 7 files changed, 93 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Sema/debug-93066.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 270b0a1e01307..0ad0a80c21521 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8777,6 +8777,9 @@ def err_typecheck_incomplete_type_not_modifiable_lvalue : Error<
 def err_typecheck_lvalue_casts_not_supported : Error<
   "assignment to cast is illegal, lvalue casts are not supported">;
 
+def note_typecheck_expression_not_modifiable_lvalue : Note<
+  "add '*' to dereference it">; 
+
 def err_typecheck_duplicate_vector_components_not_mlvalue : Error<
   "vector is not assignable (contains duplicate components)">;
 def err_block_decl_ref_not_modifiable_lvalue : Error<
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ff9c5ead36dcf..125aaf8981358 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13367,6 +13367,21 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
         if (!DiagnosticEmitted) {
           S.Diag(Loc, diag::err_typecheck_assign_const)
               << ExprRange << ConstVariable << VD << VD->getType();
+          ExprResult Deref;
+          Expr *TE = const_cast<Expr *>(E);
+          {
+            Sema::TentativeAnalysisScope Trap(S);
+            Deref = S.ActOnUnaryOp(S.getCurScope(), Loc, tok::star, TE);
+          }
+          if (Deref.isUsable() &&
+              Deref.get()->isModifiableLvalue(S.Context, &Loc) ==
+                  Expr::MLV_Valid &&
+              !E->getType()->isObjCObjectPointerType()) {
+            S.Diag(Loc, diag::note_typecheck_expression_not_modifiable_lvalue)
+                << E->getSourceRange()
+                << FixItHint::CreateInsertion(E->getBeginLoc(),
+                                              "*" + VD->getNameAsString());
+          }
           DiagnosticEmitted = true;
         }
         S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
@@ -13587,10 +13602,47 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
   SourceRange Assign;
   if (Loc != OrigLoc)
     Assign = SourceRange(OrigLoc, OrigLoc);
-  if (NeedType)
+  if (NeedType) {
     S.Diag(Loc, DiagID) << E->getType() << E->getSourceRange() << Assign;
-  else
+  } else {
+    ExprResult Deref;
+    {
+      Sema::TentativeAnalysisScope Trap(S);
+      Deref = S.ActOnUnaryOp(S.getCurScope(), Loc, tok::star, E);
+    }
     S.Diag(Loc, DiagID) << E->getSourceRange() << Assign;
+    if (Deref.isUsable() &&
+        Deref.get()->isModifiableLvalue(S.Context, &Loc) == Expr::MLV_Valid) {
+      std::string exprType;
+      switch (E->getStmtClass()) {
+      case Stmt::CStyleCastExprClass: {
+        const auto *CSC = cast<CStyleCastExpr>(E);
+        exprType = CSC->getType().getAsString();
+        break;
+      }
+      case Stmt::CXXConstCastExprClass: {
+        const auto *CXXCCE = cast<CXXConstCastExpr>(E);
+        exprType = CXXCCE->getTypeAsWritten().getAsString();
+        break;
+      }
+      case Stmt::CXXReinterpretCastExprClass: {
+        const auto *CXXRCE = cast<CXXReinterpretCastExpr>(E);
+        exprType = CXXRCE->getTypeAsWritten().getAsString();
+        break;
+      }
+      case Stmt::CXXThisExprClass: {
+        exprType = "this";
+        break;
+      }
+      default: {
+      }
+      }
+      S.Diag(Loc, diag::note_typecheck_expression_not_modifiable_lvalue)
+          << E->getSourceRange() << Assign
+          << FixItHint::CreateInsertion(E->getBeginLoc(),
+                                        "*(" + exprType + ")");
+    }
+  }
   return true;
 }
 
diff --git a/clang/test/C/drs/dr1xx.c b/clang/test/C/drs/dr1xx.c
index 47538e44428c3..20e953b2c20ac 100644
--- a/clang/test/C/drs/dr1xx.c
+++ b/clang/test/C/drs/dr1xx.c
@@ -296,6 +296,7 @@ void dr126(void) {
    */
   *object = 12; /* ok */
   ++object; /* expected-error {{cannot assign to variable 'object' with const-qualified type 'const IP' (aka 'int *const')}} */
+  /* expected-note at -1 {{add '*' to dereference it}} */
 }
 
 /* WG14 DR128: yes
diff --git a/clang/test/Sema/debug-93066.cpp b/clang/test/Sema/debug-93066.cpp
new file mode 100644
index 0000000000000..8e9c382a63bbe
--- /dev/null
+++ b/clang/test/Sema/debug-93066.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+
+struct S {
+  void f() {
+    ++this; // expected-error {{expression is not assignable}}
+    // expected-note at -1 {{add '*' to dereference it}}
+  }
+
+  void g() const {
+    ++this; // expected-error {{expression is not assignable}}
+  }
+};
+
+void f(int* a, int* const b, const int* const c, __UINTPTR_TYPE__ d) {
+  (int*)d = 4; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+  // expected-note at -1 {{add '*' to dereference it}}
+    
+  ++a;
+  ++b; // expected-error {{cannot assign to variable 'b' with const-qualified type 'int *const'}}
+  // expected-note at -1 {{add '*' to dereference it}}
+  // expected-note@* {{variable 'b' declared const here}}
+  ++c; // expected-error {{cannot assign to variable 'c' with const-qualified type 'const int *const'}}
+  // expected-note@* {{variable 'c' declared const here}}
+
+  reinterpret_cast<int*>(42) += 3; // expected-error {{expression is not assignable}}
+  // expected-note at -1 {{add '*' to dereference it}}
+    
+  const int x = 42;
+  (const_cast<int*>(&x)) += 3; // expected-error {{expression is not assignable}}
+  // expected-note at -1 {{add '*' to dereference it}}
+}
diff --git a/clang/test/Sema/exprs.c b/clang/test/Sema/exprs.c
index 3203d961dd0a4..a5b7268f4f527 100644
--- a/clang/test/Sema/exprs.c
+++ b/clang/test/Sema/exprs.c
@@ -65,8 +65,10 @@ void test4(void) {
 
 void test5(int *X, float *P) {
   (float*)X = P;   // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+  // expected-note at -1 {{add '*' to dereference it}}
 #define FOO ((float*) X)
   FOO = P;   // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+  // expected-note at -1 {{add '*' to dereference it}}
 }
 
 void test6(void) {
diff --git a/clang/test/Sema/va_arg_x86_32.c b/clang/test/Sema/va_arg_x86_32.c
index 86a6a8881f54b..55d21f787a6f0 100644
--- a/clang/test/Sema/va_arg_x86_32.c
+++ b/clang/test/Sema/va_arg_x86_32.c
@@ -2,5 +2,6 @@
 
 int a(void) {
   __builtin_va_arg((char*)0, int); // expected-error {{expression is not assignable}}
+  // expected-note at -1 {{add '*' to dereference it}}
   __builtin_va_arg((void*){0}, int); // expected-error {{first argument to 'va_arg' is of type 'void *'}}
 }
diff --git a/clang/test/SemaObjCXX/sel-address.mm b/clang/test/SemaObjCXX/sel-address.mm
index e5661af341691..4f9b985989e00 100644
--- a/clang/test/SemaObjCXX/sel-address.mm
+++ b/clang/test/SemaObjCXX/sel-address.mm
@@ -10,6 +10,7 @@ void h() {
   SEL* ps = &s;
 
   @selector(dealloc) = s;  // expected-error {{expression is not assignable}}
+  // expected-note at -1 {{add '*' to dereference it}}
 
   SEL* ps2 = &@selector(dealloc);
 



More information about the cfe-commits mailing list