Skip to content

Commit 6dec67c

Browse files
committed
[clang] Fix-it hint for ++this -> ++*this when deref is modifiable
Resolves #93066
1 parent 1430405 commit 6dec67c

File tree

6 files changed

+51
-2
lines changed

6 files changed

+51
-2
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8777,6 +8777,9 @@ def err_typecheck_incomplete_type_not_modifiable_lvalue : Error<
87778777
def err_typecheck_lvalue_casts_not_supported : Error<
87788778
"assignment to cast is illegal, lvalue casts are not supported">;
87798779

8780+
def note_typecheck_expression_not_modifiable_lvalue : Note<
8781+
"add '*' to dereference it">;
8782+
87808783
def err_typecheck_duplicate_vector_components_not_mlvalue : Error<
87818784
"vector is not assignable (contains duplicate components)">;
87828785
def err_block_decl_ref_not_modifiable_lvalue : Error<

clang/lib/Sema/SemaExpr.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13367,6 +13367,8 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
1336713367
if (!DiagnosticEmitted) {
1336813368
S.Diag(Loc, diag::err_typecheck_assign_const)
1336913369
<< ExprRange << ConstVariable << VD << VD->getType();
13370+
S.Diag(Loc, diag::note_typecheck_expression_not_modifiable_lvalue)
13371+
<< E->getSourceRange();
1337013372
DiagnosticEmitted = true;
1337113373
}
1337213374
S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
@@ -13587,10 +13589,22 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
1358713589
SourceRange Assign;
1358813590
if (Loc != OrigLoc)
1358913591
Assign = SourceRange(OrigLoc, OrigLoc);
13590-
if (NeedType)
13592+
if (NeedType) {
1359113593
S.Diag(Loc, DiagID) << E->getType() << E->getSourceRange() << Assign;
13592-
else
13594+
} else {
13595+
ExprResult Deref;
13596+
{
13597+
Sema::TentativeAnalysisScope Trap(S);
13598+
Deref = S.ActOnUnaryOp(S.getCurScope(), Loc, tok::star, E);
13599+
}
1359313600
S.Diag(Loc, DiagID) << E->getSourceRange() << Assign;
13601+
if (Deref.isUsable() &&
13602+
Deref.get()->isModifiableLvalue(S.Context, &Loc) == Expr::MLV_Valid) {
13603+
S.Diag(Loc, diag::note_typecheck_expression_not_modifiable_lvalue)
13604+
<< E->getSourceRange() << Assign;
13605+
FixItHint::CreateInsertion(E->getBeginLoc(), "++*this");
13606+
}
13607+
}
1359413608
return true;
1359513609
}
1359613610

clang/test/Sema/debug-93066.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
2+
3+
struct S {
4+
void f() {
5+
++this; // expected-error {{expression is not assignable}}
6+
// expected-note@-1 {{add '*' to dereference it}}
7+
}
8+
9+
void g() const {
10+
++this; // expected-error {{expression is not assignable}}
11+
}
12+
};
13+
14+
void f(int* a, int* const b, const int* const c, __UINTPTR_TYPE__ d) {
15+
(int*)d = 4; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
16+
// expected-note@-1 {{add '*' to dereference it}}
17+
18+
++a;
19+
++b; // expected-error {{cannot assign to variable 'b' with const-qualified type 'int *const'}}
20+
// expected-note@-1 {{add '*' to dereference it}}
21+
// expected-note@* {{variable 'b' declared const here}}
22+
++c; // expected-error {{cannot assign to variable 'c' with const-qualified type 'const int *const'}}
23+
// expected-note@-1 {{add '*' to dereference it}}
24+
// expected-note@* {{variable 'c' declared const here}}
25+
26+
reinterpret_cast<int*>(42) += 3; // expected-error {{expression is not assignable}}
27+
// expected-note@-1 {{add '*' to dereference it}}
28+
}

clang/test/Sema/exprs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,10 @@ void test4(void) {
6565

6666
void test5(int *X, float *P) {
6767
(float*)X = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
68+
// expected-note@-1 {{add '*' to dereference it}}
6869
#define FOO ((float*) X)
6970
FOO = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
71+
// expected-note@-1 {{add '*' to dereference it}}
7072
}
7173

7274
void test6(void) {

clang/test/Sema/va_arg_x86_32.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22

33
int a(void) {
44
__builtin_va_arg((char*)0, int); // expected-error {{expression is not assignable}}
5+
// expected-note@-1 {{add '*' to dereference it}}
56
__builtin_va_arg((void*){0}, int); // expected-error {{first argument to 'va_arg' is of type 'void *'}}
67
}

clang/test/SemaObjCXX/sel-address.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ void h() {
1010
SEL* ps = &s;
1111

1212
@selector(dealloc) = s; // expected-error {{expression is not assignable}}
13+
// expected-note@-1 {{add '*' to dereference it}}
1314

1415
SEL* ps2 = &@selector(dealloc);
1516

0 commit comments

Comments
 (0)