https://github.com/Rajveer100 updated https://github.com/llvm/llvm-project/pull/94159
>From 1a9ef88a6fec33521ecdfe9d7e6d5ebc8d0805a5 Mon Sep 17 00:00:00 2001 From: Rajveer <rajveer.develo...@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 | 23 ++++++++++++-- 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 | 8 +++++ 7 files changed, 67 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..cc6e29c186bd4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13273,6 +13273,22 @@ enum { ConstUnknown, // Keep as last element }; +static void MaybeSuggestDerefFixIt(Sema &S, const Expr *E, SourceLocation Loc) { + 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(), "*"); + } +} + /// 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 @@ -13367,6 +13383,7 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E, if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstVariable << VD << VD->getType(); + MaybeSuggestDerefFixIt(S, E, Loc); DiagnosticEmitted = true; } S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) @@ -13587,10 +13604,12 @@ 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 { S.Diag(Loc, DiagID) << E->getSourceRange() << Assign; + MaybeSuggestDerefFixIt(S, E, Loc); + } 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@-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@-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@-1 {{add '*' to dereference it}} + + ++a; + ++b; // expected-error {{cannot assign to variable 'b' with const-qualified type 'int *const'}} + // expected-note@-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@-1 {{add '*' to dereference it}} + + const int x = 42; + (const_cast<int*>(&x)) += 3; // expected-error {{expression is not assignable}} + // expected-note@-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@-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@-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@-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..3c03ad9fe8bc0 100644 --- a/clang/test/SemaObjCXX/sel-address.mm +++ b/clang/test/SemaObjCXX/sel-address.mm @@ -9,7 +9,15 @@ void h() { SEL s = @selector(dealloc); SEL* ps = &s; + /* + FIXME: https://github.com/llvm/llvm-project/pull/94159 + + This would assign the value of s to the SEL object pointed to by @selector(dealloc). However, in Objective-C, selectors are not pointers, they are special compile-time constructs representing method names, and they are immutable, so you cannot assign values to them. + + Therefore, this syntax is not valid for selectors in Objective-C. + */ @selector(dealloc) = s; // expected-error {{expression is not assignable}} + // expected-note@-1 {{add '*' to dereference it}} SEL* ps2 = &@selector(dealloc); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits