[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
Tue Jun 4 07:01:14 PDT 2024
https://github.com/Rajveer100 updated https://github.com/llvm/llvm-project/pull/94159
>From 6dec67c1fe9b64881a7b4f97f2341b2fdf7db48b 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 | 18 ++++++++++--
clang/test/Sema/debug-93066.cpp | 28 +++++++++++++++++++
clang/test/Sema/exprs.c | 2 ++
clang/test/Sema/va_arg_x86_32.c | 1 +
clang/test/SemaObjCXX/sel-address.mm | 1 +
6 files changed, 51 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..62da33e64bf7b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13367,6 +13367,8 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
if (!DiagnosticEmitted) {
S.Diag(Loc, diag::err_typecheck_assign_const)
<< ExprRange << ConstVariable << VD << VD->getType();
+ S.Diag(Loc, diag::note_typecheck_expression_not_modifiable_lvalue)
+ << E->getSourceRange();
DiagnosticEmitted = true;
}
S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
@@ -13587,10 +13589,22 @@ 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) {
+ S.Diag(Loc, diag::note_typecheck_expression_not_modifiable_lvalue)
+ << E->getSourceRange() << Assign;
+ FixItHint::CreateInsertion(E->getBeginLoc(), "++*this");
+ }
+ }
return true;
}
diff --git a/clang/test/Sema/debug-93066.cpp b/clang/test/Sema/debug-93066.cpp
new file mode 100644
index 0000000000000..e0bd87fb810ef
--- /dev/null
+++ b/clang/test/Sema/debug-93066.cpp
@@ -0,0 +1,28 @@
+// 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 at -1 {{add '*' to dereference it}}
+ // 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}}
+}
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